SELECT INTO eine Tabellenvariable in T-SQL

372

Ich habe eine komplexe SELECT-Abfrage erhalten, aus der ich alle Zeilen in eine Tabellenvariable einfügen möchte, aber T-SQL lässt dies nicht zu.

In diesem Sinne können Sie keine Tabellenvariable mit SELECT INTO- oder INSERT EXEC-Abfragen verwenden. http://odetocode.com/Articles/365.aspx

Kurzes Beispiel:

declare @userData TABLE(
                        name varchar(30) NOT NULL,
                        oldlocation varchar(30) NOT NULL
                       )

SELECT name, location
INTO @userData
FROM myTable
    INNER JOIN otherTable ON ...
WHERE age > 30

Die Daten in der Tabellenvariablen werden später verwendet, um sie wieder in verschiedene Tabellen einzufügen / zu aktualisieren (meistens Kopie derselben Daten mit geringfügigen Aktualisierungen). Das Ziel wäre es, das Skript einfach ein bisschen lesbarer und leichter anpassbar zu machen, als es SELECT INTOdirekt in die richtigen Tabellen zu bringen. Die Leistung ist kein Problem, da sie rowcountrelativ klein ist und nur bei Bedarf manuell ausgeführt wird.
... oder sag mir einfach, ob ich alles falsch mache.

Indrek
quelle

Antworten:

601

Versuchen Sie so etwas:

DECLARE @userData TABLE(
    name varchar(30) NOT NULL,
    oldlocation varchar(30) NOT NULL
);

INSERT INTO @userData (name, oldlocation)
SELECT name, location FROM myTable
INNER JOIN otherTable ON ...
WHERE age > 30;
CristiC
quelle
2
Wenn Sie "SELECT name, location FROM myTable" als Werte auswählen, die Sie in die UserData-Tabelle einfügen, spielt es keine Rolle, ob die Namen der Variablen in der Auswahl mit den Namen in der Tabellendefinition übereinstimmen. Sie wählen 'Name', um in die Variable 'Name' von UserData zu gelangen, aber Sie wählen 'Ort' aus und weisen ihn irgendwie der Variablen 'oldlocation' von UserData zu. Wird SQL diese nur automatisch zuordnen oder wird es eine Ausnahme auslösen?
Aran Mulholland
Es spielt keine Rolle, nur der Spaltentyp.
CristiC
5
Wow, das macht Sinn, aber gleichzeitig fühlt sich der Parser in mir irgendwie beleidigt :)
Aran Mulholland
Ich kann anscheinend nicht in der Lage sein, dies in UPDATE-Anweisung (en) zu verwenden: Hauptlink
Paul-Sebastian Manole
1
Wenn Sie in einer Einfügeanweisung die Spalten nicht explizit deklarieren, werden sie in der Reihenfolge zugeordnet, die in der ursprünglichen Anweisung create table deklariert wurde, genau wie select *. Daher wird die Position in der select-Anweisung der alten Position in der @ usData-Tabelle zugeordnet, da sich die Position in der Ergebnismenge der Auswahl an Position 2 befindet und die alte Position in der Tabellendefinition Spalte 2 ist. Das heißt, tu das niemals. Auf die Datenbankreihenfolge von Spalten oder Zeilen kann man sich nicht verlassen. Seien Sie immer explizit darüber.
Absmiths
94

Der Zweck von SELECT INTOist (gemäß den Dokumenten, meine Betonung)

So erstellen Sie eine neue Tabelle aus Werten in einer anderen Tabelle

Aber Sie bereits haben eine Zieltabelle! Also was du willst ist

Die INSERTAnweisung fügt einer Tabelle eine oder mehrere neue Zeilen hinzu

Sie können die Datenwerte folgendermaßen angeben:

...

Mithilfe einer SELECTUnterabfrage können Sie die Datenwerte für eine oder mehrere Zeilen angeben, z.

  INSERT INTO MyTable 
 (PriKey, Description)
        SELECT ForeignKey, Description
        FROM SomeView

In dieser Syntax darf MyTablees sich um eine Tabellenvariable handeln.

AakashM
quelle
1
Ich wünschte wirklich, die akzeptierte Antwort würde diese Informationen enthalten!
Davie Brown
Ich bekomme, dass MyTable dabei "Ungültiger Objektname" ist, daher fehlt in dieser Antwort etwas.
Mike Flynn
@MikeFlynn MyTablehier ist ein Platzhalter für den Namen Ihrer tatsächlichen Tabelle . Ich glaube nicht, dass es echte Datenbanken mit einer Tabelle namens MyTable...
AakashM
Und wenn ich mit SELECT INTO ... eine Tabellenvariable erstellen / deklarieren möchte? Zum Beispiel, um die Spalten der Tabellenvariablen als t1.somecolumn, t1.othercolumn, t2 zu definieren. *
Armando
27

Sie können auch allgemeine Tabellenausdrücke verwenden, um temporäre Datasets zu speichern. Sie sind eleganter und adhoc-freundlicher:

WITH userData (name, oldlocation)
AS
(
  SELECT name, location 
  FROM   myTable    INNER JOIN 
         otherTable ON ...
  WHERE  age>30
)
SELECT * 
FROM   userData -- you can also reuse the recordset in subqueries and joins
nanestev
quelle
Ich liebe das! Vielen Dank.
Fourpastmidnight
Ich glaube nicht, dass dies eine Kopie macht. Wenn Sie aus userData löschen oder aktualisieren, werden dann nicht die Datensätze in Ihren Originaltabellen gelöscht und aktualisiert?
Atreeon
Ja, DELETE und UPDATE auf dem CTE ändern die
Quelltabelle,
2
Der Nachteil dabei ist, dass Sie die CTE-Tabelle nur in den unmittelbar folgenden Befehlen verwenden können. Wenn Sie aus irgendeinem Grund mehr als einen Durchgang durch die Ergebnismenge durchführen müssen, funktioniert CTE nicht. Das OP scheint zu implizieren, dass mehrere Änderungen vorgenommen werden. In diesem Fall funktioniert dies nicht. "Die Daten in der Tabellenvariablen werden später verwendet, um sie wieder in verschiedene Tabellen einzufügen / zu aktualisieren (meistens Kopie derselben Daten mit Minor Aktualisierung)."
Tony
16

Sie können versuchen, temporäre Tabellen zu verwenden, wenn Sie dies nicht über eine Anwendung tun. (Es kann in Ordnung sein, dies manuell auszuführen)

SELECT name, location INTO #userData FROM myTable
INNER JOIN otherTable ON ...
WHERE age>30

Sie überspringen den Aufwand, die Tabelle auf diese Weise zu deklarieren ... Hilft bei Ad-hoc-Abfragen ... Dadurch wird eine lokale temporäre Tabelle erstellt, die für andere Sitzungen nur sichtbar ist, wenn Sie sich in derselben Sitzung befinden. Möglicherweise ein Problem, wenn Sie eine Abfrage über eine App ausführen.

Wenn Sie es für die Ausführung in einer App benötigen, verwenden Sie die folgenden Variablen:

DECLARE @userData TABLE(
    name varchar(30) NOT NULL,
    oldlocation varchar(30) NOT NULL
);

INSERT INTO @userData
SELECT name, location FROM myTable
INNER JOIN otherTable ON ...
WHERE age > 30;

Bearbeiten: Wie viele von Ihnen erwähnt haben, wurde die Sichtbarkeit der Sitzung von der Verbindung aus aktualisiert. Das Erstellen von temporären Tabellen ist keine Option für Webanwendungen, da Sitzungen wiederverwendet werden können. Halten Sie sich in diesen Fällen an temporäre Variablen

Mulki
quelle
2
Entschuldigung, ich habe vergessen zu erwähnen, dass ich keine Rechte für CREATE TABLE habe.
Indrek
6
Das Erstellen einer Temperatur hat etwas mehr Aufwand.
Paparazzo
2
Die Verwendung einer temporären Tabelle ist nicht immer sicher. Zum Beispiel Webdienste. Bei Webservices mit einer einzelnen Verbindung, um die maximale Verbindung auf dem Server zu begrenzen UND SQL ein wenig mehr zu schützen, ist die temporäre Tabelle für JEDE durchlaufende Abfrage vorhanden und kann jemanden überschreiben, der sie gerade verwendet.
Franck
12
@Franck - Wenn Sie eine globale temporäre Tabelle (zwei Hash-Präfixe) verwenden, sind Sie korrekt. Eine lokale temporäre Tabelle (ein Hash-Präfix) wird jedoch auf eine einzelne Sitzung (auch als einzelne Verbindung bezeichnet) isoliert, sodass keine Parallelitätsprobleme auftreten, auf die Sie anspielen, es sei denn, Sie verwenden eine einzige Verbindung für alle Anforderungen (nicht) empfohlen). Die möglichen Auswirkungen auf die Leistung bleiben jedoch bestehen.
Maf748
@GazB Sicher, jede Aussage mit Nebenwirkung ist von der Verwendung in a ausgeschlossen function. Nach meiner Erfahrung bedeutet dies in den meisten Fällen, in denen jemand glaubt, solche Aussagen zu benötigen, tatsächlich, dass er seine function- oder zumindest die Umgestaltung auf a - überdenken sollte procedure. Zumindest für mich selbst sprechen. :-)
underscore_d
8

Versuchen Sie INSERTanstelle von SELECT INTO:

INSERT @UserData   
SELECT name, location etc.
Noel Abrahams
quelle
5

Erstellen Sie zuerst eine temporäre Tabelle:

Schritt 1:

create table #tblOm_Temp (

    Name varchar(100),
    Age Int ,
    RollNumber bigint
)

** Schritt 2: ** Fügen Sie einen Wert in die Temp-Tabelle ein.

insert into #tblom_temp values('Om Pandey',102,1347)

Schritt 3: Deklarieren Sie eine Tabellenvariable, um temporäre Tabellendaten zu speichern.

declare   @tblOm_Variable table(

    Name Varchar(100),
    Age int,
    RollNumber bigint
)

Schritt 4: Wählen Sie einen Wert aus der temporären Tabelle aus und fügen Sie ihn in die Tabellenvariable ein.

insert into @tblOm_Variable select * from #tblom_temp

Schließlich wird der Wert aus einer temporären Tabelle in die Tabellenvariable eingefügt

Schritt 5: Kann den eingefügten Wert in der Tabellenvariablen überprüfen.

select * from @tblOm_Variable
404 Nicht gefunden
quelle
1

OK, jetzt kann ich mit genügend Aufwand Folgendes in @table einfügen:

INSERT @TempWithheldTable SELECT
a.SuspendedReason, a.SuspendedNotes, a.SuspendedBy, a.ReasonCode FROM OPENROWSET (BULK 'C: \ DataBases \ WithHeld.csv', FORMATFILE = N'C: \ DataBases \ Format.txt ',
ERRORFILE = N'C: \ Temp \ MovieLensRatings.txt ') AS a;

Die Hauptsache hier ist die Auswahl der einzufügenden Spalten.

RahulJha
quelle
Ich erhalte die Kompilierungsfehlermeldung "Muss die Tabellenvariable" @TempWithheldTable "deklarieren
atreeon
-5

Ein Grund für die Verwendung von SELECT INTO besteht darin, dass Sie IDENTITY verwenden können:

SELECT IDENTITY(INT,1,1) AS Id, name
INTO #MyTable 
FROM (SELECT name FROM AnotherTable) AS t

Dies würde mit einer Tabellenvariablen nicht funktionieren, was zu schade ist ...

MOHCTP
quelle
6
Sie können jedoch eine Tabellenvariable mit einer IDENTITYSpalte deklarieren .
Martin Smith