2010-05-27 15 views
12

Sembra che i #temptables creati utilizzando SQL dinamico tramite il metodo stringa EXECUTE abbiano un ambito diverso e non possano essere referenziati da SQL "fissi" nella stessa stored procedure. Tuttavia, posso fare riferimento a una tabella temporanea creata da un'istruzione SQL dinamica in un SQL dinamico di sottosessione, ma sembra che una stored procedure non restituisca un risultato di query a un client chiamante a meno che l'SQL non venga risolto.T-SQL SQL dinamico e tabelle temporanee

Uno scenario a 2 tabelle semplice: Ho 2 tabelle. Chiamiamoli Ordini e Articoli. L'ordine ha una chiave primaria di OrderId e gli articoli hanno una chiave primaria di ItemId. Items.OrderId è la chiave esterna per identificare l'ordine genitore. Un ordine può avere da 1 a n elementi.

Desidero essere in grado di fornire un'interfaccia di tipo "query builder" molto flessibile all'utente per consentire all'utente di selezionare gli elementi che desidera vedere. I criteri di filtro possono essere basati su campi dalla tabella Articoli e/o dalla tabella Ordine genitore. Se un articolo soddisfa la condizione di filtro inclusa e condizione sull'ordine genitore, se ne esiste uno, l'articolo deve essere restituito nella query e l'ordine principale.

In genere, suppongo, la maggior parte delle persone costruisce un join tra la tabella Articolo e le tabelle Ordine genitore. Vorrei invece eseguire 2 query separate. Uno per restituire tutti gli Articoli idonei e l'altro per restituire tutti gli Ordini genitore distinti. Il motivo è due volte e si può o non si può essere d'accordo.

Il primo motivo è che ho bisogno di interrogare tutte le colonne nella tabella Ordine genitore e se avessi fatto una singola query per unire la tabella Ordini alla tabella Articoli, avrei repoeated le informazioni dell'Ordine più volte. Dal momento che in genere sono presenti un numero elevato di articoli per ordine, vorrei evitare questo perché ciò comporterebbe il trasferimento di molti più dati verso un client grasso. Invece, come accennato, vorrei restituire le due tabelle individualmente in un set di dati e utilizzare le due tabelle all'interno per popolare un ordine personalizzato e oggetti client Elementi figlio. (Non conosco ancora abbastanza su LINQ o Entity Framework. Costruisco i miei oggetti a mano). La seconda ragione per cui vorrei restituire due tabelle invece di una è perché ho già un'altra procedura che restituisce tutti gli elementi per un determinato OrderId insieme all'ordine genitore e vorrei utilizzare lo stesso approccio a due tabelle in modo che io potrebbe riutilizzare il codice client per popolare i miei oggetti Ordine e Cliente personalizzati dai 2 datatables restituiti.

quello che speravo di fare era questa:

costruire una stringa SQL dinamico sul client, che unisce la tabella ordini al tavolo Elementi e di appositi filtri su ogni tavolo, come specificato dal filtro personalizzato creato sul Winform app fat-client. La build di SQL sul client avrebbe guardato qualcosa di simile:

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 */ 
    " 

Poi, vorrei chiamare una stored procedure,

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) 

Il problema di questo approccio è che tavolo #ItemsToQuery, dal momento che era creato da SQL dinamico, è inaccessibile dai seguenti 2 SQL statici e se modifico SQL statici in dinamico, nessun risultato viene passato al fat client.

3 intorno vengono in mente, ma io sono aspetto per uno migliore:

1) La prima SQL potrebbe essere eseguita eseguendo lo SQL costruito in modo dinamico dal client. I risultati potrebbero quindi essere passati come tabella a una versione modificata della procedura memorizzata sopra. Conosco i dati della tabella di passaggio come XML. Se l'ho fatto, il proc memorizzato potrebbe quindi inserire i dati in una tabella temporanea utilizzando un SQL statico che, poiché è stato creato da SQL dinamico, potrebbe quindi essere interrogato senza problemi.(Potrei anche indagare su come passare il nuovo param di tipo Table invece di XML.) Tuttavia, vorrei evitare di passare a elenchi potenzialmente grandi per una stored procedure.

2) Potrei eseguire tutte le query dal client.

Il primo sarebbe qualcosa di simile:

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) 

Questo mi dà ancora con la possibilità di riutilizzare il mio cliente codice oggetto-sided popolazione perché gli Ordini ed elementi continuano ad essere restituito in due diverse tabelle.

Ho la sensazione che potrei avere alcune opzioni che utilizzano un tipo di dati Tabella all'interno del mio proc memorizzato, ma anche questo è nuovo per me e gradirei un po 'di cucchiaio che si nutre di quello.

Se hai anche scansionato fino a questo punto in quello che ho scritto, sono sorpreso, ma se così fosse, non capirò mai i tuoi pensieri su come ottenere il meglio.

+0

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

risposta

17

è necessario creare il vostro tavolo prima poi sarà disponibile in SQL dinamico

questo funziona

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

select * from #temp3 

questo non funzionerà

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

select * from #temp2 

In altre parole:

  1. creare tabella temporanea

  2. eseguire proc

  3. selezionare dalla tabella temporanea

Ecco Esempio 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

Penso che funzioni anche questo: inserire in #temptable exec ('select ?? from ??'); Il problema –

+4

è quando non conosciamo la definizione delle colonne, e allora? – Muflix

0

set di risultati da SQL dinamico vengono restituiti al client. L'ho fatto parecchio.

Hai ragione sui problemi con la condivisione di dati tramite tabelle temporali e variabili e cose simili tra SQL e l'SQL dinamico che genera.

Credo che nel cercare di ottenere il vostro piano di lavoro temporanea, probabilmente avete ottenuto alcune cose confuse, perché si può sicuramente ottenere i dati da un SP che esegue SQL dinamico:

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 

anche:

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

se crei la tabella temporanea nel proc non funzionerà, devi prima creare la tabella temporanea, quindi puoi popolarla nel proc .. vedi anche il mio esempio – SQLMenace

+0

@SQLMenace - Vedo quello che stai dicendo. Il mio punto era che POTETE restituire gli insiemi dall'SQL dinamico (e possono usare le loro proprie tabelle temporanee e ritornare da loro). Aggiungerò un secondo esempio. –

2

vi consiglierei vivamente di avere una lettura attraverso http://www.sommarskog.se/arrays-in-sql-2005.html

Personalmente mi piace l'approccio di passare una lista di testo delimitato da virgole, allora pars con la funzione text to table e unendovi ad essa. L'approccio alla tabella temporanea può funzionare se lo si crea prima nella connessione. Ma si sente un po 'disordinato.

+1

Preferirei passare XML piuttosto che CSV. Sebbene più dettagliato, consente la flessibilità di modificare e passare colonne aggiuntive. E SQL sa già come analizzare XML. Ma ho visto un esempio per il passaggio di un set di dati del client in una variabile della tabella del lato server. Molto pulito. Anche se, tuttavia, è meno desiderabile della tabella temporanea IMHO, è un approccio che è meno probabile scalare. – 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 

OPPURE 2o Metodo.
Questo funzionerà. Ma è necessario fare particolare attenzione alla variabile globale.

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

    select * from ##temp2 

END 

Non dimenticate di eliminare ## oggetto temp2 mannually una volta il vostro obiettivo sarà ottenere raggiunto.

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

Nota: Non utilizzare questo metodo se non conoscere la struttura completa sulla base di dati.

Problemi correlati