2016-07-22 16 views
0

ここに私がしようとしていることがあります。私はテーブル、列、および列の値の名前を入力するだけのストアドプロシージャを作成しようとしているし、そのテーブル内のその値に関連付けられているレコードを削除します。これを行う簡単な方法はありますか?私はSQLについてあまりよく知らず、まだそれについて学んでいます。TableName、ColumnName、およびColumnValueをパラメータとして使用してDELETEステートメントストアドプロシージャを作成する方法

これまで私がこれまで持っていたことは次のとおりです。一般的に

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文から実行して渡す必要があります。このため、動的SQLから_and_にデータを簡単に渡すことができるため、sp_executesqlを使用する必要があります。 – Nicarus

答えて

0

カップルの問題

まず、あなたは(テーブルの名前)を必要としない

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

あなたは

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

適切なスキーマの接頭辞を含めるようにしてくださいテーブル名に特殊文字が含まれている場合は、大括弧で囲んでください。

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

@Valueは文字列なので、@SQLの値を計算するときには、一重引用符で囲む必要があります。あなたはこのように、2つの単一引用符を使用して、それをエスケープする必要がある文字列に単一引用符を挿入するには:

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をできるようにしたい場合は、代わりに

EXEC sp_ExecuteSql @SQL 

そして最後に、素晴らしいアイデアではありません私は、ストアドプロシージャのminute--

この種のためにeditorializeせsp_executesqlを使用します。柔軟性があり、他の言語にはそういった考え方は普通は賢いですが、データベース環境ではこのアプローチが問題を引き起こします。 sp_executeSqlを呼び出すために昇格された権限が必要であり、プリコンパイル/パフォーマンスに関する問題がある(SQLが事前にわかっていないため、SQL Serverはそれぞれ新しいクエリプランを生成する必要があります)あなたがこれを呼び出すたびに)呼び出し元がテーブルとカラム名の値を与えることができるので、このdelete文が効率的でインデックスを使用するかどうか、あるいはテーブルが大きく、列は索引付けされません。

適切な方法は、条件に基づいて削除する必要がある各データのユースケースに固有の厳密な型指定の入力を持つ一連の適切なストアドプロシージャを作成することです。データベースエンジニアは、柔軟な対応を試みるべきではありません。あなたは、人々が正確に何を必要としているのかを考えることを強制されなければなりません。これは、人々がルールに従って、R/Iをそのまま維持し、インデックスを効率的に使用するための唯一の方法です。

はい、これは繰り返して冗長な作業のようですが、c'est la vie。追加の入力が気に入らなければ、CRUD操作用のコードを生成するためのツールがあります。

+0

@valueの周りに単一引用符を入れるかどうかは、(最適化の目的のために)列のデータ型に依存します。 – jyao

0

John Wuが提供した情報の一部に加えて、triggersがテーブルやものにある場合、@@ROWCOUNTは正確ではない可能性があります。これらの問題は両方とも回避できますnvarchar()にキャストし、のOUTPUT句を使用して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)を使用します。OUTPUTsp_executesqlからパラメータを使用すると、カウントを返すことができます。

SQLで何かできることがあっても、必ずしもそうであるとは限りません。

関連する問題