2016-07-22 4 views
0

Вот что я пытаюсь сделать. Я пытаюсь создать хранимую процедуру, где я могу просто ввести имя таблицы, столбца и значения столбца, и он удалит записи, связанные с этим значением в этой таблице. Есть ли простой способ сделать это? Я не слишком много знаю о SQL и все еще об этом узнал.Как создать инструкцию DELETE Сохраненная процедура с использованием TableName, ColumnName и ColumnValue в качестве параметров передачи

Вот что у меня есть.

ALTER PROCEDURE [dbo].[name of stored procedure] 
@TABLE_NAME varchar(50), 
@COLUMN_NAME varchar(50), 
@VALUE varchar(5) 

AS 
BEGIN 
    SET NOCOUNT ON; 

    DECLARE @RowsDeleted int; 
    DECLARE @sql VARCHAR(500); 

    SET @sql = 'DELETE FROM (name of table).' + @TABLE_NAME + ' WHERE ' + @COLUMN_NAME + '=' + '@VALUE' 
    EXEC(@sql) 

    SET @[email protected]@ROWCOUNT 
END 
GO 
+1

Ожидается, что принятый ответ на [этот связанный вопрос] (http://stackoverflow.com/questions/2838490/table-name-as-variable) будет вдохновлять. Посетите [link] (http://www.sommarskog.se/dynamic_sql.html) в ответе для более подробной информации. –

+0

Что случилось с вашей текущей процедурой? – FLICKER

+0

Я не думаю, что '@@ ROWCOUNT' работает в этом контексте. Вам понадобится это, чтобы выполнить и передать из динамического оператора SQL. Вот почему вы должны использовать 'sp_executesql', потому что вы можете легко передавать данные в _and_ из динамического SQL. – Nicarus

ответ

0

Пара вопросы

Во-первых, вам не нужно (имя таблицы)

SET @sql = 'DELETE FROM ' + @TABLE_NAME + etc. 

В общем, вы должны попытаться включить соответствующий префикс Schema

SET @sql = 'DELETE FROM dbo.' + @TABLE_NAME + etc. 

И в случае, если ваше имя таблицы имеет специальные символы, возможно, оно должно быть заключено в скобки

SET @sql = 'DELETE FROM dbo.[' + @TABLE_NAME + ']' + etc. 

Поскольку @Value - это строка, вы должны окружать ее одинарными кавычками при вычислении значения для @SQL. Чтобы вставить апостроф в строку, вы должны избежать этого, используя две одинарные кавычки, например:

SET @SQL = 'DELETE FROM dbo.[' + @TABLE_NAME + '] WHERE [' + @COLUMN_NAME + '] = '''' + @VALUE + '''' 

Если @VALUE сама содержит апостроф, вся эта вещь сломается, так что вам нужно бежать, что а

SET @SQL = 'DELETE FROM dbo.[' + @TABLE_NAME + '] WHERE [' + @COLUMN_NAME + '] = '''' + REPLACE(@VALUE,'''','''''') + '''' 

также @@ ROWCOUNT не заселить от EXEC. Если вы хотите, чтобы иметь возможность читать @@ ROWCOUNT, используйте sp_executesql вместо

EXEC sp_ExecuteSql @SQL 

И, наконец, позвольте мне тенденциозно интерпретировать материал для minute--

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

Правильный подход состоит в том, чтобы иметь ряд соответствующих хранимых процедур с строго типизированными входами, которые являются специфическими для каждого случая использования данных, где вам нужно удалить на основе критериев. Инженеры базы данных не должны пытаться сделать вещи гибкими; вы должны заставить людей задуматься о том, что именно они понадобятся, и реализовать это и только это. Это единственный способ обеспечить, чтобы люди следовали правилам, сохраняя неизменное R/I, эффективное использование индексов и т. Д.

Да, это может показаться повторяющейся и избыточной работой, но c'est la vie. Существуют средства для генерации кода для операций CRUD, если вам не нравится дополнительная набрав.

+0

Является ли установка сингулярной цитаты вокруг @value действительно зависящей от типа данных столбца (для целей оптимизации) – jyao

0

В дополнение к некоторой информации John Wu при условии, что вам нужно беспокоиться о типах данных, и @@ROWCOUNT может быть неточным, если есть triggers на ваших столах и вещах ..... Вы можете обойти обе эти проблемы, хотя путем литья по nvarchar() и с использованием OUTPUT с temp table, чтобы выполнить COUNT().

Так просто для развлечения здесь есть способ, вы можете сделать это:

CREATE PROCEDURE dbo.[ProcName] 
@TableName SYSNAME 
,@ColumnName SYSNAME 
,@Value NVARCHAR(MAX) 
,@RecordCount INT OUTPUT 
AS 

BEGIN 

    DECLARE @SQL NVARCHAR(1000) 

    SET @SQL = N'IF OBJECT_ID(''tempdb..#DeletedOutput'') IS NOT NULL 
     BEGIN 
      DROP TABLE #DeletedOutput 
     END 

    CREATE TABLE #DeletedOutput (
     ID INT IDENTITY(1,1) 
     ColumnValue NVARCHAR(MAX) 
    ) 

    DELETE FROM dbo.' + QUOTENAME(@TableName) + ' 
    OUTPUT deleted.' + QUOTENAME(@ColumnName) + ' INTO #DeletedOutput (ColumnValue) 
    WHERE CAST(' + QUOTENAME(@ColumnName) + ' AS NVARCHAR(MAX)) = ' + CHAR(39) + @Value + CHAR(39) + ' 

    SELECT @RecordCountOUT = COUNT(ID) FROM #DeletedOutput 

    IF OBJECT_ID(''tempdb..#DeletedOutput'') IS NOT NULL 
     BEGIN 
      DROP TABLE #DeletedOutput 
     END' 

    DECLARE @ParmDefinition NVARCHAR(200) = N'@RecordCountOUT INT OUTPUT' 

    EXECUTE sp_executesql @SQL, @ParmDefinition, @RecordCountOUT = @RecordCount OUTPUT 

END 

Таким образом, использование QOUTENAME поможет от нападения инъекции, но не может быть совершенным. И я использую CHAR(39) вместо escape-последовательности для одной кавычки по значению, потому что мне легче, когда строит строки в этой точке .... Используя параметр OUTPUT от sp_executesql, вы все равно можете вернуть свой счет.

Имейте в виду, что только вы можете что-то сделать в SQL, это не всегда означает, что вы должны.

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

  • Нет связанных вопросов^_^