SELECCIONAR EN una variable de tabla en T-SQL

372

Obtuve una consulta SELECT compleja, desde la cual me gustaría insertar todas las filas en una variable de tabla, pero T-SQL no lo permite.

En la misma línea, no puede usar una variable de tabla con las consultas SELECT INTO o INSERT EXEC. http://odetocode.com/Articles/365.aspx

Breve ejemplo:

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

Los datos en la variable de la tabla se usarían luego para insertar / actualizar nuevamente en diferentes tablas (principalmente copia de los mismos datos con actualizaciones menores). El objetivo de esto sería simplemente hacer que el script sea un poco más legible y más fácilmente personalizable que hacerlo SELECT INTOdirectamente en las tablas correctas. El rendimiento no es un problema, ya que rowcountes bastante pequeño y solo se ejecuta manualmente cuando es necesario.
... o simplemente dime si lo estoy haciendo todo mal.

Indrek
fuente

Respuestas:

601

Intenta algo como esto:

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
fuente
2
Si "SELECCIONA nombre, ubicación de myTable" como los valores que va a insertar en la tabla UserData, no importa si los nombres de las variables en la selección coinciden con los nombres en la definición de la tabla. Está seleccionando 'nombre' para ir a la variable 'nombre' UserData pero está seleccionando 'ubicación' y de alguna manera asignándolo a la variable 'oldlocation' de UserData. ¿SQL solo los asignará automáticamente o arrojará algún tipo de excepción?
Aran Mulholland
No importa el nombre, solo el tipo de columna.
CristiC
55
Wow, eso tiene sentido, pero al mismo tiempo el analizador en mí se siente ofendido :)
Aran Mulholland
Parece que no puedo usar esto en la (s) declaración (es) de ACTUALIZACIÓN: enlace esencial
Paul-Sebastian Manole
1
En una declaración de inserción, si no declara las columnas explícitamente, entonces se asignan en el orden declarado en la declaración de creación de la tabla original, tal como lo hace select *. Por lo tanto, la ubicación en la instrucción select se asigna a la ubicación antigua en la tabla @userData porque la ubicación está en la posición 2 en el conjunto de resultados de la selección, y la ubicación antigua es la columna 2 en la definición de la tabla. Dicho esto, nunca hagas esto. No se debe confiar en el orden de las bases de datos de columnas o filas. Siempre sea explícito sobre esto.
Herreros
94

El propósito de SELECT INTOes (según los documentos, mi énfasis)

Para crear una nueva tabla a partir de valores en otra tabla

¡Pero ya tienes una mesa objetivo! Entonces lo que quieres es

La INSERTdeclaración agrega una o más filas nuevas a una tabla

Puede especificar los valores de datos de las siguientes maneras:

...

Al utilizar una SELECTsubconsulta para especificar los valores de datos para una o más filas, como:

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

Y en esta sintaxis, está permitidoMyTable que sea una variable de tabla.

AakashM
fuente
1
¡Realmente deseo que la respuesta aceptada incluya esta información!
Davie Brown
Obtengo que MyTable es "Nombre de objeto no válido" haciendo esto, por lo que falta algo en esta respuesta.
Mike Flynn
@MikeFlynn MyTableaquí es un marcador de posición para el nombre de su tabla real . No creo que haya bases de datos reales con una tabla llamada MyTable...
AakashM
¿Y si quiero crear / declarar una variable de tabla con SELECT INTO ...? Por ejemplo, para definir las columnas de la variable de tabla como t1.somecolumn, t1.othercolumn, t2. *
Armando
27

También puede usar expresiones de tabla comunes para almacenar conjuntos de datos temporales. Son más elegantes y amigables:

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
fuente
¡Me gusta esto! Gracias.
fourpastmidnight
No creo que esto haga una copia, si elimina o actualiza desde userData, ¿no eliminará y actualizará los registros en sus tablas originales?
atreeon
Sí, borrar y actualizar en el CTE modificará la tabla de origen, siempre que el CTE no hace referencia a varias tablas utilizando uniones, sindicatos, etc.
nanestev
2
La desventaja de esto es que solo puede usar la tabla CTE en los siguientes comandos. Si necesita hacer más de un pase a través del conjunto de resultados por alguna razón, CTE no funcionará. El OP parece implicar que se realizarán múltiples modificaciones, en cuyo caso esto no funcionará. actualizaciones) ".
Tony
16

Podría intentar usar tablas temporales ... si no lo está haciendo desde una aplicación. (Puede estar bien ejecutar esto manualmente)

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

Omite el esfuerzo de declarar la tabla de esa manera ... Ayuda para consultas ad hoc ... Esto crea una tabla temporal local que no será visible para otras sesiones a menos que esté en la misma sesión. Tal vez sea un problema si está ejecutando una consulta desde una aplicación.

si necesita que se ejecute en una aplicación, use variables declaradas de esta manera:

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;

Editar: muchos de ustedes mencionaron visibilidad actualizada a la sesión desde la conexión. La creación de tablas temporales no es una opción para aplicaciones web, ya que las sesiones se pueden reutilizar, atenerse a las variables temporales en esos casos

Mulki
fuente
2
Lo sentimos, olvidé mencionar que no tengo derechos para CREATE TABLE.
Indrek
66
Crear una temperatura tiene un poco más de sobrecarga.
paparazzo
2
Usar la tabla temporal no siempre es seguro. Por ejemplo, servicios web. Con servicios web con una sola conexión para limitar la conexión máxima en el servidor Y proteger SQL un poco más, la tabla temporal existirá para CADA consulta que pase y puede sobrescribir a alguien que la esté usando actualmente.
Franck
12
@Franck: si usa una tabla temporal global (dos prefijos hash) está en lo correcto. Sin embargo, una tabla temporal local (un prefijo hash) se aislará en una sola sesión (también conocida como conexión única), por lo que no habrá problemas de concurrencia a los que se esté aludiendo a menos que esté usando una conexión única para todas las solicitudes (no aconsejado). Sin embargo, las posibles implicaciones de rendimiento permanecen.
maf748
@GazB Claro, cualquier declaración con un efecto secundario está excluida de ser utilizada en a function. En mi experiencia, en la mayoría de los casos en los que alguien piensa que necesita tales declaraciones, esto en realidad significa que debe repensar su function- o al menos refactorizar a procedure. Hablando por mí mismo, al menos. :-)
underscore_d
8

Intenta usar en INSERTlugar de SELECT INTO:

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

Primero cree una tabla temporal:

Paso 1:

create table #tblOm_Temp (

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

** Paso 2: ** Insertar algún valor en la tabla Temp.

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

Paso 3: declarar una variable de tabla para contener los datos de la tabla temporal.

declare   @tblOm_Variable table(

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

Paso 4: seleccione el valor de la tabla temporal e insértelo en la variable de tabla.

insert into @tblOm_Variable select * from #tblom_temp

Finalmente, el valor se inserta desde una tabla temporal a la variable Tabla

Paso 5: puede verificar el valor insertado en la variable de tabla.

select * from @tblOm_Variable
404 No encontrado
fuente
1

OK, ahora con suficiente esfuerzo puedo insertar en @table usando lo siguiente:

INSERTAR @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 ') COMO a;

Lo principal aquí es seleccionar columnas para insertar.

RahulJha
fuente
Recibo un mensaje de error de compilación "Debo declarar la variable de tabla" @TempWithheldTable "
atreeon
-5

Una razón para usar SELECT INTO es que le permite usar IDENTITY:

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

Esto no funcionaría con una variable de tabla, lo cual es una lástima ...

MOHCTP
fuente
66
Sin IDENTITYembargo, puede declarar una variable de tabla con una columna.
Martin Smith