SQL Server динамические запросы - PullRequest
2 голосов
/ 05 ноября 2008

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

Пример:

Common: tblCommon
Specific: tblSpecific

Есть ли способ передать имя "tblSpecific" в одну хранимую процедуру как переменную, как показано ниже?

SELECT ....
FROM tblCommon c
INNER JOIN @TABLE s on c.primaryKey = s.foreignKey

Ответы [ 6 ]

10 голосов
/ 05 ноября 2008

Это можно сделать с помощью динамически генерируемого SQL, который запускается с помощью хранимой процедуры sp_executesql ().

Как правило, вы передаете требуемое имя таблицы в вашу основную процедуру, создаете строку ncharvar для SQL, который хотите выполнить, и передаете его в sp_executesql.

Проклятие и благословение Динамического SQL о лучшей странице, которую я видел для описания всех входов и выходов.

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

3 голосов
/ 05 ноября 2008

Да, вы можете динамически сгенерировать оператор SQL и затем выполнить его.

Например,

DECLARE @specificTableName nvarchar(50)
DECLARE @specificColumnName nvarchar(50)

SET @specificTableName = 'tblSpecific'
SET @specificColumnName = 'colSpecific'

DECLARE @sql nvarchar(4000)

set @sql = 'SELECT ... FROM tblCommon c INNER JOIN ' +
@specificTableName + ' s ON c.PrimaryKey = s.' + @specificColumnName


exec (@sql)
1 голос
/ 22 мая 2013

Сформулируйте / обработайте ваш запрос как строку, затем вызовите EXECUTE(@SQLStatement)

1 голос
/ 05 ноября 2008

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

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

Ответ - справочная таблица. Создайте таблицу «таблиц», которая содержит имя каждой из ваших конкретных таблиц. Это должно выглядеть примерно так:

CREATE TABLE [tables] (table_name sysname)

Затем вы можете написать запрос, который будет выглядеть примерно так:

SELECT @tblSpecific = table_name FROM [tables] WHERE table_name = @tblSpecific

Теперь вам просто нужно проверить, является ли @tblSpecific 1014 *. Если это не так, тогда безопасно использовать в динамическом операторе SQL (и динамический SQL здесь, в конечном итоге, является вашим единственным вариантом: даже определенная пользователем функция делает это на каком-то уровне).

Да, и еще одна вещь - мой выбор имен и типов для таблицы поиска не случаен. В стандарте SQL уже есть такая таблица (ну, в любом случае, представление). Просто используйте INFORMATION_SCHEMA.Tables.

0 голосов
/ 05 ноября 2008

Я бы сохранил их как отдельную хранимую процедуру.

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

Вы либо получите список из 15 вызовов более сложной хранимой процедуры с параметрами, либо получите эквивалентный список более простых хранимых процедур. И если ваш параметр является именем таблицы, это не будет типом параметризованного sp, который выполняется эффективно. Что касается табличного подхода, он все еще является менее эффективной и более опасной динамической хранимой процедурой. Скорее всего, записи таблицы будут введены неправильно, за исключением таблицы, любые ошибки в именах таблиц будут еще менее заметны. И связь возросла, и сплоченность снизилась (оба двинулись в неправильном направлении).

0 голосов
/ 05 ноября 2008

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

SELECT ....
FROM tblCommon c
INNER JOIN dbo.SomeFuntionThatReturnsData(@someparam) s on c.primaryKey = s.foreignKey
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...