2010-05-27 21 views
12

Wygląda na to, że # zwolnienia utworzone przy użyciu dynamicznego SQL za pomocą metody łańcuchowej EXECUTE mają inny zakres i nie można odwoływać się do "stałych" instrukcji SQL w tej samej przechowywanej procedurze. Mogę jednak odwołać się do tabeli tymczasowej utworzonej przez dynamiczną instrukcję SQL w dynamicznym podciągu SQL, ale wydaje się, że procedura składowana nie zwraca wyniku zapytania do klienta wywołującego, chyba że SQL jest naprawiony.T-SQL Dynamiczne tablice SQL i temp.

Prosty scenariusz 2 stołowy: Mam 2 tabele. Nazwijmy je Zamówieniami i Przedmiotami. Zamówienie ma klucz podstawowy z OrderId, a Items posiada klucz podstawowy ItemId. Items.OrderId to klucz obcy identyfikujący zamówienie rodzica. Zamówienie może zawierać od 1 do n pozycji.

Chcę być w stanie zapewnić użytkownikowi bardzo elastyczny interfejs typu "konstruktor zapytań", umożliwiający użytkownikowi wybór elementów, które chce zobaczyć. Kryteria filtrów mogą opierać się na polach z tabeli Items i/lub z rodzicielskiej tabeli Order. Jeśli element spełnia warunek filtru, w tym warunek w zamówieniu nadrzędnym, jeśli taki istnieje, element powinien zostać zwrócony zarówno w zapytaniu, jak i nadrzędnym zamówieniu.

Zazwyczaj, jak przypuszczam, większość ludzi tworzyłaby sprzężenie między tabelą Przedmiotów a tabelami Rozkazów nadrzędnych. Chciałbym zamiast tego wykonać 2 oddzielne zapytania. Jeden, aby zwrócić wszystkie pozycje kwalifikujące, a drugi, aby zwrócić wszystkie oddzielne zamówienia rodzicielskie. Powód jest dwojaki i możesz lub nie możesz się z tym zgodzić.

Pierwszy powód jest taki, że muszę zapytać o wszystkie kolumny w tabeli zamówień nadrzędnych, a gdybym zrobił jedno zapytanie, aby przyłączyć się do tabeli Zamówienia do tabeli Przedmiotów, wielokrotnie przekazywałbym informacje o zamówieniu. Ponieważ na jedno Zamówienie składa się zazwyczaj duża liczba elementów, chciałbym tego uniknąć, ponieważ spowodowałoby to przeniesienie znacznie większej ilości danych do grubego klienta. Zamiast tego, jak już wspomniałem, chciałbym zwrócić dwie tabele pojedynczo w zbiorze danych i użyć dwóch tabel w celu zapełnienia niestandardowych obiektów zamówień i obiektów potomnych przedmiotów. (Nie wiem jeszcze wystarczająco dużo o LINQ lub Entity Framework, ręcznie buduję obiekty). Drugim powodem, dla którego chciałbym zwrócić dwie tabele zamiast jednej, jest to, że mam już inną procedurę, która zwraca wszystkie przedmioty dla danego OrderId wraz z rodzica Order i chciałbym użyć tego samego podejścia 2-table tak, żebym może ponownie użyć kodu klienta, aby zapełnić moje niestandardowe obiekty zamówienia i klienta z 2 zwróconymi danymi.

Co miałem nadzieję zrobić to w ten sposób:

Construct dynamiczny SQL ciąg na Klienta, która łączy tabelę zleceń tabeli elementów i filtry odpowiednie na każdym stole, jak określono przez filtr niestandardowy utworzonego na Winform aplikacja fat-client. Kompilacja SQL na kliencie będzie wyglądał mniej więcej tak:

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

Następnie nazwałbym procedurę przechowywaną,

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) 

Problem z tego podejścia jest to, że #ItemsToQuery stolik, ponieważ było utworzony przez dynamiczny SQL, jest niedostępny z następujących 2 statycznych instrukcji SQL i jeśli zmienię statyczne SQL na dynamiczne, żadne wyniki nie są przekazywane do grubego klienta.

3 wokół przyjść do głowy, ale jestem wygląd lepszy:

1) Pierwszy SQL można przeprowadzić poprzez wykonanie dynamicznego SQL skonstruowaną z klientem. Wyniki można następnie przekazać jako tabelę do zmodyfikowanej wersji powyższej procedury przechowywanej. Jestem zaznajomiony z przekazywaniem danych tabeli jako XML. Gdybym to zrobił, przechowywany proces mógł następnie wstawić dane do tabeli tymczasowej za pomocą statycznego SQL, który, ponieważ został utworzony przez dynamiczny SQL, mógł być następnie zapytany bez problemu.(Mógłbym również zbadać przekazanie nowego parametru typu Tabela zamiast XML.) Chciałbym jednak uniknąć podawania potencjalnie dużych list do procedury składowanej.

2) Mogłem wykonać wszystkie zapytania od klienta.

Pierwszy byłoby coś takiego:

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) 

To wciąż daje mi możliwość ponownego wykorzystania mój klient jednostronny kodu obiektowego zaludnienia ponieważ Zamówienia i przedmioty nadal być zwrócony w dwóch różnych tabel.

Mam przeczucie, że mogę mieć pewne opcje przy użyciu typu danych tabeli w moim zapisanym proc, ale jest to również dla mnie nowe i doceniłbym trochę łyżki żywienia na tym.

Jeśli nawet przeskanowałeś tak daleko w tym, co napisałem, jestem zaskoczony, ale jeśli tak, to doceniam każdą z twoich myśli na temat tego, jak osiągnąć to najlepiej.

+0

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

Odpowiedz

17

trzeba utworzyć tabelę pierwszy wtedy będzie ona dostępna w dynamicznym SQL

to działa

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

select * from #temp3 

to nie będzie działać

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

select * from #temp2 

Innymi słowy:

  1. utworzyć tabelę temp

  2. wykonać proc

  3. wybierz z tabeli temp

Oto pełna przykład

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

Myślę, że to też działa: włóż do #wyłączalnego exec ('select ?? from ??'); –

+4

problem polega na tym, że nie znamy definicji kolumn, a co dopiero? – Muflix

0

zestawy wynikają z dynamicznego SQL są zwracane do klienta. Zrobiłem to całkiem sporo.

Masz rację, jeśli chodzi o problemy z udostępnianiem danych poprzez tabele tymczasowe i zmienne oraz podobne kwestie między SQL i generowanym przez niego dynamicznym SQL.

myślę, próbując uzyskać Temp tabeli, prawdopodobnie dostał kilka rzeczy mylić, bo na pewno można uzyskać dane z SP, który wykonuje dynamiczny SQL:

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 

również:

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

jeśli utworzysz tabelę tymczasową w proc, to nie zadziała, musisz najpierw utworzyć tabelę tymczasową, następnie możesz ją wypełnić w proc .. patrz także mój przykład – SQLMenace

+0

@ SQLMenace - Widzę, co mówisz. Chodzi mi o to, że MOŻESZ powrócić zestawy z dynamicznego SQL (i mogą korzystać z własnych tabel tymczasowych i wrócić z nich). Dodam drugi przykład. –

2

Chciałbym zdecydowanie sugerują, że masz przeczytać http://www.sommarskog.se/arrays-in-sql-2005.html

Osobiście lubię podejście przekazując listę tekstowy rozdzielany przecinkami, a następnie pars przy pomocy funkcji tekstu do tabeli i dołączania do niego. Podejście do tabeli tymczasowej może działać, jeśli utworzysz je jako pierwsze w połączeniu. Ale czuje się nieco bardziej zawikłany.

+1

Chciałbym wcześniej przekazać XML niż CSV. Chociaż jest bardziej szczegółowy, pozwala na elastyczność w modyfikowaniu i przekazywaniu dodatkowych kolumn. A SQL już wie, jak parsować XML. Ale widziałem przykład przekazywania zestawu danych klienta do zmiennej tabeli po stronie serwera. Bardzo czysto. Mimo to, jest to mniej pożądane niż IMHO w tabeli temp, która jest mniej prawdopodobna w skali. – 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 

LUB 2. Metoda.
To zadziała. Musisz jednak zadbać o zmienną globalną.

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

    select * from ##temp2 

END 

Nie zapomnij usunąć ## temp2 obiektu raz po osiągnięciu celu.

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

Uwaga: Dont użyć tej metody, jeśli nie znamy pełnej struktury na bazie.

Powiązane problemy