Как параматизировать хранимую процедуру T-SQL, которая удаляет таблицу? - PullRequest
2 голосов
/ 09 июля 2009

Я после простой хранимой процедуры для удаления таблиц. Вот моя первая попытка:

CREATE PROC bsp_susf_DeleteTable (@TableName char)
AS
IF EXISTS (SELECT name FROM sysobjects WHERE name = @TableName)
BEGIN
DROP TABLE @TableName
END

Когда я анализирую это в MS Query Analyzer, я получаю следующую ошибку:

Server: Msg 170, Level 15, State 1, Procedure bsp_susf_DeleteTable, Line 6
Line 6: Incorrect syntax near '@TableName'.

Какой тип имеет смысл, потому что нормальный SQL для отдельной таблицы будет:

IF EXISTS (SELECT name FROM sysobjects WHERE name = 'tbl_XYZ')
BEGIN
    DROP TABLE tbl_XYZ
END

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

Так может ли быть создана хранимая процедура для этого? Или я должен копировать, ЕСЛИ СУЩЕСТВУЕТ ... везде?

Ответы [ 3 ]

3 голосов
/ 09 июля 2009

Вы должны быть в состоянии использовать динамический sql:

declare @sql varchar(max)
if exists (select name from sysobjects where name = @TableName)
BEGIN
   set @sql = 'drop table ' + @TableName
   exec(@sql)
END

Надеюсь, это поможет.

Обновление: да, вы можете сделать @sql меньше, это был только быстрый пример. Также обратите внимание на другие комментарии о атаках SQL-инъекций

2 голосов
/ 09 июля 2009

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

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

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

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

0 голосов
/ 09 июля 2009

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

Редактировать: ОДНАКО, я не рекомендую этого, потому что кто-то может перейти в sql, а не TableName и вызвать все виды замечательных проблем. См. Sql инъекцию для получения дополнительной информации.

Лучше всего создать для этого параметризованный запрос на стороне клиента. Например, в C # я бы сделал что-то вроде:

// EDIT 2: on second thought, ignore this code; it probably won't work
SqlCommand sc = new SqlCommand();
sc.Connection = someConnection;
sc.CommandType = Command.Text;
sc.CommandText = "drop table @tablename";
sc.Parameters.AddWithValue("@tablename", "the_table_name");
sc.ExecuteNonQuery();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...