2010-05-27 20 views
12

Parece que las #temptables creadas mediante SQL dinámico a través del método de cadena EXECUTE tienen un alcance diferente y no pueden ser referenciadas por SQL "fijas" en el mismo procedimiento almacenado. Sin embargo, puedo hacer referencia a una tabla temporal creada por una declaración de SQL dinámico en una SQL dinámica de subsecuencia, pero parece que un procedimiento almacenado no devuelve un resultado de consulta a un cliente llamante a menos que se solucione el SQL.Tablas dinámicas y SQL dinámicas de T-SQL

Un escenario simple de 2 tablas: Tengo 2 tablas. Vamos a llamarlos Pedidos y Artículos. El pedido tiene una clave principal de OrderId y Items tiene una clave principal de ItemId. Items.OrderId es la clave externa para identificar el pedido principal. Una orden puede tener de 1 a n elementos.

Deseo poder proporcionar al usuario una interfaz de tipo "creador de consultas" muy flexible para permitirle al usuario seleccionar qué elementos desea ver. Los criterios de filtro pueden basarse en campos de la tabla Elementos y/o de la tabla de pedidos principal. Si un artículo cumple con la condición de filtro, que incluye una condición en el pedido principal, si existe, el elemento debe devolverse en la consulta, así como en el pedido principal.

Por lo general, supongo que la mayoría de las personas construiría una unión entre la tabla de elementos y las tablas de pedidos principales. Me gustaría realizar 2 consultas separadas en su lugar. Uno para devolver todos los elementos calificados y el otro para devolver todos los pedidos principales distintos. La razón es doble y puede o no estar de acuerdo.

La primera razón es que necesito consultar todas las columnas en la tabla de pedidos principal y si hice una sola consulta para unirme a la tabla de Pedidos en la tabla Artículos, estaría reubicando la información del pedido varias veces. Dado que normalmente hay una gran cantidad de artículos por pedido, me gustaría evitar esto porque daría lugar a que se transfieran muchos más datos a un cliente gordo. En cambio, como se mencionó, me gustaría devolver las dos tablas de manera individual en un conjunto de datos y usar las dos tablas para completar un pedido personalizado y objetos de cliente secundarios. (Aún no sé lo suficiente sobre LINQ o Entity Framework. Construyo mis objetos a mano). La segunda razón por la que me gustaría devolver dos tablas en lugar de una es porque ya tengo otro procedimiento que devuelve todos los artículos para un OrderId dado junto con el orden principal y me gustaría usar el mismo método de dos tablas para que podría reutilizar el código del cliente para rellenar mis objetos ordenados de Cliente y Cliente de las 2 tablas de datos devueltas.

lo que esperaba hacer era esto:

Construir una cadena SQL dinámico en el cliente, que se une a la tabla de pedidos a la mesa y filtros apropiados en cada tabla de artículos según lo especificado por el filtro personalizado creado en el Winform aplicación fat-client. La acumulación de SQL en el cliente se habría visto algo como esto:

TempSQL = " 

    INSERT INTO #ItemsToQuery 
     OrderId, ItemsId 
    FROM 
     Orders, Items 
    WHERE 
     Orders.OrderID = Items.OrderId AND 
     /* Some unpredictable Order filters go here */ 
     AND 
     /* Some unpredictable Items filters go here */ 
    " 

Entonces, yo llamaría un procedimiento almacenado,

CREATE PROCEDURE GetItemsAndOrders(@tempSql as text) 
    Execute (@tempSQL) --to create the #ItemsToQuery table 

SELECT * FROM Items WHERE Items.ItemId IN (SELECT ItemId FROM #ItemsToQuery) 

SELECT * FROM Orders WHERE Orders.OrderId IN (SELECT DISTINCT OrderId FROM #ItemsToQuery) 

El problema con este enfoque es que la tabla #ItemsToQuery, ya que era creado por SQL dinámico, es inaccesible desde los siguientes 2 SQL estáticos y si cambio los SQL estáticos a dinámico, no se devuelven resultados al cliente "gordo".

3 alrededor vienen a la mente, pero estoy mirada por uno mejor:

1) La primera SQL podría llevarse a cabo mediante la ejecución del SQL de forma dinámica construida desde el cliente. Los resultados podrían pasarse como una tabla a una versión modificada del procedimiento almacenado anterior. Estoy familiarizado con pasar los datos de la tabla como XML. Si hiciera esto, el proceso almacenado podría insertar los datos en una tabla temporal utilizando un SQL estático que, debido a que fue creado por SQL dinámico, podría consultarse sin problemas.(También podría investigar el paso del nuevo param Tipo de tabla en lugar de XML.) Sin embargo, me gustaría evitar pasar listas potencialmente grandes a un procedimiento almacenado.

2) Pude realizar todas las consultas del cliente.

La primera sería algo como esto:

SELECT Items.* FROM Orders, Items WHERE Order.OrderId = Items.OrderId AND (dynamic filter) 
SELECT Orders.* FROM Orders, Items WHERE Order.OrderId = Items.OrderId AND (dynamic filter) 

Esto todavía me da la posibilidad de reutilizar el código objeto población de clientes caras debido a los pedidos y artículos siguen siendo devuelto en dos tablas diferentes.

Tengo la sensación de que podría tener algunas opciones para usar un tipo de datos de tabla dentro de mi proceso almacenado, pero eso también es nuevo para mí y agradecería un poco de cuchara alimentándome con eso.

Si echó un vistazo hasta aquí en lo que escribí, estoy sorprendido, pero si es así, me gustaría apreciar cualquiera de sus pensamientos sobre cómo lograr esto mejor.

+0

TLDR: http://www.urbandictionary.com/define.php?term=TLDR –

Respuesta

17

lo que necesita para crear su primera tabla a continuación, que estará disponible en el SQL dinámico

esto funciona

create table #temp3 (id int) 
exec ('insert #temp3 values(1)') 

select * from #temp3 

esto no funcionará

exec ('create table #temp2 (id int) 
    insert #temp2 values(1)') 

select * from #temp2 

En otras palabras:

  1. crear tabla temporal

  2. ejecutar proc

  3. de selección de tabla temporal

Aquí es Ejemplo completo

create proc prTest2 @var varchar(100) 
as 
exec (@var) 
go 

create table #temp (id int) 

exec prTest2 'insert #temp values(1)' 

select * from #temp 
+0

Creo que esto también funciona: inserte en #temptable exec ('select ?? from ??'); –

+4

problema es cuando no sabemos la definición de columnas, ¿qué tal entonces? – Muflix

0

conjuntos de resultados de SQL dinámico se devuelven al cliente. He hecho esto bastante.

Tiene razón sobre los problemas con el intercambio de datos a través de tablas y variables temporales y cosas así entre el SQL y el SQL dinámico que genera.

Creo que al tratar de obtener su temperatura de trabajo de mesa, que probablemente han conseguido algunas cosas confusas, porque definitivamente se puede obtener datos de un SP que ejecuta SQL dinámico:

USE SandBox 
GO 

CREATE PROCEDURE usp_DynTest(@table_type AS VARCHAR(255)) 
AS 
BEGIN 
    DECLARE @sql AS VARCHAR(MAX) = 'SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = ''' + @table_type + '''' 
    EXEC (@sql) 
END 
GO 

EXEC usp_DynTest 'BASE TABLE' 
GO 

EXEC usp_DynTest 'VIEW' 
GO 

DROP PROCEDURE usp_DynTest 
GO 

también:

USE SandBox 
GO 

CREATE PROCEDURE usp_DynTest(@table_type AS VARCHAR(255)) 
AS 
BEGIN 
    DECLARE @sql AS VARCHAR(MAX) = 'SELECT * INTO #temp FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = ''' + @table_type + '''; SELECT * FROM #temp;' 
    EXEC (@sql) 
END 
GO 

EXEC usp_DynTest 'BASE TABLE' 
GO 

EXEC usp_DynTest 'VIEW' 
GO 

DROP PROCEDURE usp_DynTest 
GO 
+0

si crea la tabla temporal en el proceso, no funcionará, primero debe crear la tabla temporal, luego puede poblarla en el proceso ... vea también mi ejemplo – SQLMenace

+0

@SQLMenace - Veo lo que está diciendo. Mi punto es que PUEDE devolver conjuntos de SQL dinámico (y pueden usar sus propias tablas temporales y regresar de ellas). Agregaré un segundo ejemplo. –

2

me gustaría sugerir fuertemente que tiene una lectura a través http://www.sommarskog.se/arrays-in-sql-2005.html

Personalmente me gusta el enfoque de transmitir una lista de texto delimitado por comas, a continuación, pars ing con función de texto a tabla y uniéndose a ella. El enfoque de tabla temporal puede funcionar si lo crea primero en la conexión. Pero se siente un poco más desordenado.

+1

Preferiría pasar XML que CSV. Aunque es más detallado, permite flexibilidad para modificar y pasar columnas adicionales. Y SQL ya sabe cómo analizar XML. Pero he visto un ejemplo para pasar un conjunto de datos de cliente a una variable de tabla lateral del servidor. Muy limpio. Sin embargo, incluso eso es menos deseable que la tabla temporal en mi humilde opinión, que es un enfoque que tiene menos probabilidades de escalar. – ChadD

3
DECLARE @DynamicQuery NVarchar(MAX) 
    Set @DynamicQuery='Select * into #temp from (select * from tablename) alias 
    select * from #temp 
    drop table #temp' 
    exec sp_executesql @DynamicQuery 

O 2nd Method.
Esto funcionará. Pero debe tener especial cuidado con la variable global.

IF OBJECT_ID('tempdb..##temp2') IS NULL 
BEGIN 
    exec ('create table ##temp2 (id int) 
     insert ##temp2 values(1)') 

    select * from ##temp2 

END 

No olvides eliminar ## temp2 object mannually una vez que hayas logrado tu objetivo.

IF OBJECT_ID('tempdb..##temp2') IS NOT NULL 
DROP Table ##temp2 

Nota: No utilice este método si usted no sabe la estructura completa de la base de datos.