2010-05-27 3 views
12

Похоже, что #temptables, созданные с использованием динамического SQL с помощью строкового метода EXECUTE, имеют разную область видимости и не могут ссылаться на «исправленные» SQL-запросы в той же хранимой процедуре. Тем не менее, я могу ссылаться на временную таблицу, созданную динамическим оператором SQL в динамическом SQL подпоследовательности, но кажется, что хранимая процедура не возвращает результат запроса вызывающему клиенту, если SQL не исправлена.T-SQL Динамические таблицы SQL и Temp

Простой сценарий с двумя таблицами: У меня есть 2 стола. Назовем их «Заказы и предметы». У ордена есть первичный ключ OrderId, а элементы имеют первичный ключ ItemId. Items.OrderId - это внешний ключ для идентификации родительского ордера. Заказ может содержать от 1 до n элементов.

Я хочу иметь возможность предоставить очень гибкий интерфейс типа «запрос строителя», чтобы пользователь мог выбрать, какие элементы он хочет видеть. Критерии фильтра могут быть основаны на полях из таблицы Items и/или из родительской таблицы заказов. Если элемент соответствует условию фильтра, включая условие и условие для родительского ордера, если он существует, элемент должен быть возвращен в запросе, а также родительский заказ.

Обычно, я полагаю, большинство людей создавали бы соединение между таблицей Item и родительскими таблицами заказов. Вместо этого я хотел бы выполнить 2 отдельных запроса. Один, чтобы вернуть все квалификационные элементы и другие, чтобы вернуть все отдельные родительские ордеры. Причина в два раза, и вы можете или не можете согласиться.

Первая причина заключается в том, что мне нужно запросить все столбцы в родительской таблице заказов, и если бы я сделал один запрос, чтобы присоединиться к таблице Orders в таблице Items, я бы несколько раз возвращал информацию о заказе. Поскольку на заказ обычно имеется большое количество предметов, я бы хотел этого избежать, потому что это привело бы к тому, что гораздо больше данных было передано жировому клиенту. Вместо этого, как уже упоминалось, я хотел бы вернуть две таблицы отдельно в наборе данных и использовать две таблицы внутри, чтобы заполнить пользовательские объекты Order и child Items. (Я еще недостаточно знаю о LINQ или Entity Framework. Я строю свои объекты вручную). Вторая причина, по которой я хотел бы вернуть две таблицы вместо одной, состоит в том, что у меня уже есть другая процедура, которая возвращает все элементы для данного OrderId вместе с родительским ордером, и я хотел бы использовать один и тот же подход из 2 таблиц, чтобы я может повторно использовать код клиента для заполнения моих пользовательских объектов Order и Client из возвращаемых 2 возвращаемых данных.

То, что я надеялся сделать, это:

Построить динамическую строку SQL на клиенте, который связывает таблицу заказов на таблицу Элементы и фильтры соответствующих каждой таблицы, как указано в пользовательском фильтре, созданного на Winform жирное клиентское приложение. SQL сборки на клиенте выглядел бы примерно так:

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

Тогда, я бы вызвать хранимую процедуру,

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) 

Проблема с этим подходом является то, что #ItemsToQuery стол, так как это было созданный динамическим SQL, недоступен из следующих 2 статических SQL-запросов, и если я изменил статические SQL-запросы на динамические, результаты не будут возвращены жировому клиенту.

3 вокруг прийти на ум, но я искать лучше один:

1) Первый SQL может быть выполнена путем выполнения динамически построенного SQL от клиента. Затем результаты могут быть переданы в виде таблицы в модифицированную версию вышеупомянутой хранимой процедуры. Я знаком с передачей данных таблицы как XML. Если я это сделаю, сохраненный proc может затем вставить данные во временную таблицу, используя статический SQL, который, поскольку он был создан динамическим SQL, затем может быть запрошен без проблем.(Я мог бы также расследовать передачу нового параметра типа таблицы вместо XML.) Однако я хотел бы избежать переноса потенциально больших списков в хранимую процедуру.

2) Я мог выполнять все запросы от клиента.

Первое будет что-то вроде этого:

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) 

Это все еще дает мне возможность повторно использовать мой клиент стороннего код объекта-население, так как заказы и товары продолжают быть возвращены в двух различных таблицах.

У меня есть ощущение, что у меня могут быть некоторые параметры, используя тип данных таблицы в моей хранимой процедуре, но это также ново для меня, и я был бы признателен за немного ложки, питающейся этим.

Если вы даже отсканировали это далеко в том, что я написал, я удивлен, но если это так, я буду обесценивать любые ваши мысли о том, как это сделать лучше всего.

+0

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

ответ

17

вам необходимо создать таблицу первого, то он будет доступен в динамическом SQL

это работает

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

select * from #temp3 

это не будет работать

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

select * from #temp2 

Другими словами:

  1. создать временную таблицу

  2. выполнить прок

  3. выбрать из таблицы темп

Вот полный пример

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

Я думаю, что это тоже работает: вставьте в #temptable exec ('select ?? from ??'); –

+4

Проблема в том, когда мы не знаем определения столбцов, как насчет тогда? – Muflix

0

Результат наборы из динамического SQL возвращаются клиенту. Я сделал это довольно много.

Вы правы в вопросах обмена данными через временные таблицы и переменные и т. Д. Между SQL и динамическим SQL, который он генерирует.

Я думаю, что в попытке получить временную таблицу работу, вы, вероятно, есть некоторые вещи, которые путают, потому что вы можете определенно получить данные от SP, который выполняет динамический 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 

также:

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

, если вы создаете временную таблицу в proc, это не сработает, вам нужно сначала создать временную таблицу, затем вы можете заполнить ее в proc..see также мой пример – SQLMenace

+0

@SQLMenace. Я вижу, что вы говорите. Я хотел сказать, что вы можете возвращать наборы из динамического SQL (и они могут использовать свои собственные временные таблицы и возвращаться от них). Я добавлю второй пример. –

2

я бы настоятельно рекомендуем вам иметь прочитать http://www.sommarskog.se/arrays-in-sql-2005.html

лично мне нравится подход прохождения через запятую список текста, затем Парс с помощью функции text to table и присоединения к ней. Подход таблицы temp может работать, если вы сначала создаете его в соединении. Но он чувствует себя немного грязнее.

+1

Я бы скорее прошел XML, чем CSV. Хотя он более подробен, он позволяет гибко изменять и передавать дополнительные столбцы. И SQL уже знает, как разбирать XML. Но я видел пример передачи набора данных клиента в переменную таблицы на стороне сервера. Очень чистый. Тем не менее, хотя это менее желательно, чем временная таблица IMHO, это подход, который менее вероятен для масштабирования. – 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 

ИЛИ 2-й метод.
Это будет работать. Но вам нужно больше заботиться о глобальной переменной.

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

    select * from ##temp2 

END 

Не забудьте удалить объект ## temp2 mannually, как только ваша цель будет достигнута.

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

Примечание: Не используйте этот метод, если вы не знаете всю структуру на базе данных.

Смежные вопросы