SELEZIONA IN UNA variabile di tabella in T-SQL


372

Ho una complessa query SELECT, dalla quale vorrei inserire tutte le righe in una variabile di tabella, ma T-SQL non lo consente.

Sulla stessa linea, non è possibile utilizzare una variabile di tabella con le query SELECT INTO o INSERT EXEC. http://odetocode.com/Articles/365.aspx

Breve esempio:

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

I dati nella variabile tabella verranno successivamente utilizzati per reinserirli / aggiornarli in tabelle diverse (principalmente copia degli stessi dati con aggiornamenti minori). L'obiettivo di questo sarebbe semplicemente rendere lo script un po 'più leggibile e più facilmente personalizzabile rispetto a fare SELECT INTOdirettamente nelle tabelle giuste. Le prestazioni non sono un problema, in quanto rowcountsono piuttosto piccole e vengono eseguite manualmente solo quando necessario.
... o dimmi solo se sto sbagliando tutto.

Risposte:


601

Prova qualcosa del genere:

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;

2
Se "SELEZIONA nome, posizione DA myTable" come valori che inserirai nella tabella UserData, non importa se i nomi delle variabili nella selezione corrispondono ai nomi nella definizione della tabella. Stai selezionando 'name' per accedere alla variabile 'name' UserData ma stai selezionando 'location' e in qualche modo assegnandolo alla variabile 'oldlocation' UserData. SQL li mapperà automaticamente o genererà una sorta di eccezione?
Aran Mulholland,

Non importa il nome, solo il tipo di colonna.
CristiC,

5
Wow quel senso ha senso ma allo stesso tempo il parser in me si sente offeso :)
Aran Mulholland

Non riesco a essere in grado di usarlo nelle dichiarazioni UPDATE: gist link
Paul-Sebastian Manole

1
In un'istruzione insert, se non si dichiarano esplicitamente le colonne, vengono mappate nell'ordine dichiarato nell'istruzione di creazione della tabella originale, proprio come seleziona *. Pertanto, l'ubicazione nell'istruzione select viene mappata su oldlocation nella tabella @userData poiché location è nella posizione 2 nel set di risultati della selezione e oldlocation è la colonna 2 nella definizione della tabella. Detto questo, non farlo mai. Non è necessario fare affidamento sull'ordinamento del database di colonne o righe. Sii sempre esplicito su questo.
Absmiths

94

Lo scopo di SELECT INTOè (per i documenti, la mia enfasi)

Per creare una nuova tabella dai valori in un'altra tabella

Ma tu già hai una tabella di destinazione! Quindi quello che vuoi è

L' INSERTistruzione aggiunge una o più nuove righe a una tabella

È possibile specificare i valori dei dati nei seguenti modi:

...

Utilizzando una SELECTsottoquery per specificare i valori dei dati per una o più righe, ad esempio:

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

E in questa sintassi, può MyTableessere una variabile di tabella.


1
Vorrei davvero che la risposta accettata includesse queste informazioni!
Davie Brown,

Ottengo MyTable è "Nome oggetto non valido" in questo modo, quindi manca qualcosa da questa risposta.
Mike Flynn,

@MikeFlynn MyTablequi è un segnaposto per il nome del tuo tavolo reale . Non credo ci siano veri e propri database con una tabella chiamata MyTable...
AakashM,

E se voglio creare / dichiarare una variabile di tabella con SELECT INTO ...? Ad esempio, per definire le colonne della variabile di tabella come t1.somecolumn, t1.othercolumn, t2. *
Armando

27

È inoltre possibile utilizzare espressioni di tabella comuni per archiviare set di dati temporanei. Sono più eleganti e accoglienti:

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

Ama questo! Grazie.
fourpastmidnight,

Non penso che questo ne faccia una copia, se elimini o aggiorni da userData non eliminerà e aggiornerà i record nelle tue tabelle originali?
Atreeon

Sì, DELETE e UPDATE sul CTE modificheranno la tabella di origine purché il CTE non faccia riferimento a più tabelle utilizzando join, sindacati, ecc.
nanestev

2
L'aspetto negativo di questo è che puoi usare la tabella CTE solo nei comandi immediatamente seguenti. Se è necessario eseguire più di un passaggio nel set di risultati per qualsiasi motivo, CTE non funzionerà. L'OP sembra implicare che verranno apportate più modifiche, nel qual caso ciò non funzionerà - "I dati nella variabile tabella verranno successivamente utilizzati per reinserirli / aggiornarli in tabelle diverse (principalmente copia degli stessi dati con minori gli aggiornamenti)."
Tony,

16

Potresti provare a usare tabelle temporanee ... se non lo stai facendo da un'applicazione. (Potrebbe essere ok eseguirlo manualmente)

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

Salti lo sforzo di dichiarare la tabella in quel modo ... Aiuta per le query ad hoc ... Questo crea una tabella temporanea locale che non sarà visibile ad altre sessioni se non sei nella stessa sessione. Forse un problema se stai eseguendo una query da un'app.

se necessario per l'esecuzione su un'app, utilizzare le variabili dichiarate in questo modo:

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;

Modifica: come molti di voi hanno menzionato la visibilità aggiornata della sessione dalla connessione. La creazione di tabelle temporanee non è un'opzione per le applicazioni Web, poiché le sessioni possono essere riutilizzate, attenersi alle variabili temporanee in quei casi


2
Siamo spiacenti, ho dimenticato di menzionare che non ho i diritti per CREATE TABLE.
Indrek,

6
La creazione di un temp ha un po 'più di sovraccarico.
paparazzo,

2
l'utilizzo della tabella temporanea non è sempre sicuro. Ad esempio, i servizi web. Con i servizi web con una singola connessione per limitare la connessione massima sul server E proteggere un po 'di più SQL, la tabella temporanea esisterà per OGNI query che passa e può sovrascrivere qualcuno che la sta attualmente utilizzando.
Franck,

12
@Franck - se usi una tabella temporanea globale (due prefissi hash) hai ragione. Tuttavia, una tabella temporanea locale (un prefisso hash) verrà isolata in una singola sessione (aka connessione singola), quindi non ci saranno i problemi di concorrenza a cui alludi a meno che non utilizzi una singola connessione per tutte le richieste (non consigliato). Tuttavia, rimangono le possibili implicazioni sulle prestazioni.
maf748,

@GazB Certo, qualsiasi affermazione con un effetto collaterale è esclusa dall'uso in a function. Nella mia esperienza, nella maggior parte dei casi in cui qualcuno pensa di aver bisogno di tali affermazioni, questo in realtà significa che dovrebbero ripensare il proprio function- o almeno refactor a a procedure. Parlando da solo, almeno. :-)
underscore_d

8

Prova a usare INSERTinvece di SELECT INTO:

INSERT @UserData   
SELECT name, location etc.

5

Innanzitutto crea una tabella temporanea:

Passo 1:

create table #tblOm_Temp (

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

** Passaggio 2: ** Inserire un valore nella tabella Temp.

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

Passaggio 3: dichiarare una variabile di tabella per contenere i dati della tabella temporanea.

declare   @tblOm_Variable table(

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

Passaggio 4: selezionare il valore dalla tabella temporanea e inserirlo nella variabile della tabella.

insert into @tblOm_Variable select * from #tblom_temp

Infine il valore viene inserito da una tabella temporanea alla variabile Tabella

Passaggio 5: è possibile verificare il valore inserito nella variabile di tabella.

select * from @tblOm_Variable

1

OK, ora con abbastanza sforzo sono in grado di inserire in @table usando il seguente:

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

La cosa principale qui è selezionare le colonne da inserire.


Ottengo un messaggio di errore di compilazione "Deve dichiarare la variabile di tabella" @TempWithheldTable "
Atreeon

-5

Uno dei motivi per utilizzare SELECT INTO è che ti consente di usare IDENTITY:

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

Questo non funzionerebbe con una variabile di tabella, che è troppo male ...


6
Puoi dichiarare una variabile di tabella con una IDENTITYcolonna però.
Martin Smith,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.