nvarchar в качестве аргумента запроса - PullRequest
0 голосов
/ 06 июля 2011

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

Итак ...

CREATE PROCEDURE blabla
@TableName nvarchar(50)
AS
DROP TABLE @TableName -- just an example, real queries are much longer
GO

Этот запрос дает мненеверная синтаксическая ошибка.

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

Спасибо

Ответы [ 4 ]

4 голосов
/ 06 июля 2011

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

http://www.sommarskog.se/dynamic_sql.html

По сути, выполнение того, что вы хотите сделать, имеет ряд проблем, в том числе не позволяет системе должным образом проверить наличие проблем с разрешениями перед выполнением, не удается оптимизировать хранимую процедуру и (что наиболее важно) открыть себя до SQL-инъекция. Вы можете несколько смягчить эту последнюю проблему, но она включает в себя гораздо более сложное утверждение. Вот цитата из вышеприведенной статьи:

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

Для этого вам следует использовать встроенную функцию quotename () (добавлена ​​в SQL 7). quotename () принимает два параметра: первый - строка, а второй - пара разделителей для переноса строки. Значение по умолчанию для второго параметра - []. Таким образом, quotename ('Orders') возвращает [Orders]. quotename () заботится о вложенных разделителях, поэтому, если у вас действительно сумасшедшее имя таблицы, такое как Left] Bracket, quotename () вернет [Left]] Bracket].

Обратите внимание, что при работе с именами с несколькими компонентами каждый компонент должен заключаться в кавычки отдельно. quotename ('dbo.Orders') возвращает [dbo.Orders], но это таблица в неизвестной схеме, первые четыре символа которой - это d, b, o и точка. Пока вы работаете только со схемой dbo, рекомендуется добавлять dbo в динамический SQL и передавать только имя таблицы. Если вы работаете с разными схемами, передайте схему как отдельный параметр. (Хотя вы можете использовать встроенную функцию parsename () для разделения параметра @tblname на части.)

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

1 голос
/ 06 июля 2011

Есть очень мало мест, где параметры можно использовать в T-SQL.Обычно это именно те места, где вы можете найти строку в кавычках , а не просто любое произвольное место в запросе (где запрос обязательно находится в виде строки)

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

SELECT * from Table2 where ColA = 'hello'

Но вы не можете использовать его там, где появляется Table2.Я не знаю, почему люди, кажется, ожидают, что такие вещи возможны в T-SQL, когда это вообще невозможно в большинстве других языков программирования, кроме функций стиля exec / eval.


Если у вас есть несколько таблиц, которые имеют одинаковую структуру (имена и типы столбцов), , как правило, предполагает, что на самом деле у вас должна быть одна таблица с возможно дополнительными столбцами, которые различаютмежду строками, которые изначально были бы в разных таблицах.Например, если у вас есть:

CREATE TABLE MaleEmployees (
    EmployeeNo int not null,
    Name varchar(50) not null,
)

и

CREATE TABLE FemaleEmployees (
    EmployeeNo int not null,
    Name varchar(50) not null
)

Вместо этого вы должны иметь:

CREATE TABLE Employees (
    EmployeeNo int not null,
    Name varchar(50) not null,
    Gender char(1) not null,
    constraint CK_Gender_Valid CHECK (Gender in ('M','F'))
)

Затем вы можете запросить эту таблицу Employees, независимо от того,пола, а не пытаться параметризовать имя таблицы в вашем запросе.Конечно, вышесказанное является преувеличенным примером.

0 голосов
/ 06 июля 2011

Правильный синтаксис (обратите внимание на начало):

CREATE PROCEDURE blabla
@TableName nvarchar(50)
AS
begin
DROP TABLE @TableName -- just an example, real queries are much longer
END
GO
0 голосов
/ 06 июля 2011
set @l = 'DROP TABLE ' + @TableName
exec @l

Но если это то, что вы подразумеваете под «бесконечной струной», не уверен, что вы хотите

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...