2011-07-06 4 views
0

テーブルと引数を持ち、そのテーブルに対していくつかのクエリを実行するストアドプロシージャを作成しようとしています。クエリ引数としてnvarchar

そう...

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

このクエリは私に間違った構文エラーを示します。

私はいつもsp_executesqlプロシージャを使用することができますが、無限のSQL文字列を作成する心配はありません。

おかげ

答えて

4

は、それが最善の解決策であるとき、それを正しく使用する方法ほとんどの場合、動的SQLを使用するだけでなく、させない理由について良い記事です:

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

基本的に、あなたがする探しているものを行うと、システムが正常にストアドプロシージャを最適化することができることではなく、実行する前に、アクセス許可の問題をチェックすることができ、そして(ほとんどないなど、多くの問題を、持っています重要なこと)自分自身をSQLインジェクションまで開きます。この最後の問題は多少軽減できますが、はるかに複雑なステートメントが含まれています。

ダイナミックSQLを持つプロシージャのパラメータとしてテーブルとカラムの名前を渡すことは、めったにアプリケーションコードにとってはあまりありません。 (管理タスクには完全に意味をなさけることができます)。私が言ったように、sp_executesqlのパラメータとしてテーブルやカラム名を渡すことはできませんが、SQL文字列にそれを補間する必要があります。それでも、ルーチンとしてSQLインジェクションから保護する必要があります。それはユーザー入力から来るのは悪いことかもしれません。

この目的のために、組み込み関数quotename()を使用する必要があります(SQL 7で追加されています)。 quotename()は2つのパラメータを取ります:最初の文字列、2番目の文字列は文字列を囲む区切り文字のペアです.2番目のパラメータのデフォルトは[]です。したがって、quotename( 'Orders')は[Orders]を返します。 quotename()はネストされた区切り文字を扱うので、Left] Bracketのような本当にクレイジーなテーブル名を持つ場合、quotename()は[Left]] Bracketを返します。

複数のコンポーネントで名前を操作する場合は、各コンポーネントを別々に引用する必要があります。 quotename( 'dbo.Orders')は[dbo.Orders]を返しますが、それは最初の4文字がd、b、oおよびドットである未知のスキーマのテーブルです。 dboスキーマのみで作業する場合は、動的SQLにdboを追加し、テーブル名を渡すことをお勧めします。異なるスキーマを操作する場合は、スキーマを別のパラメータとして渡します。 (組込み関数parsename()を使用して@tblnameパラメーターを分割することもできます)。

動的なステートメントを作成するための「きれいな」方法が必要だと思いますが、どのようにしてこの処理を実行できないのかは分かりませんが、ストアドプロシージャが安全であることを保証するためには、実際にステートメントをさらに複雑にする必要があります。私はこの問題を解決するために別の方法を見て非常に努力します(記事にはいくつかの提案があります)。この文を動的SQLにすることを避けることができれば、本当にすべきです。

0
set @l = 'DROP TABLE ' + @TableName 
exec @l 

しかし、それはあなたが「無限の文字列」によって何を意味するかだ場合、ないあなたが

+0

コードを投稿する場合は、テキストエディタでこれらの行を強調表示し、エディタツールバーの「コードサンプル」ボタン(「{}」)をクリックして、フォーマットや構文の強調表示をしてくださいそれ! –

+0

改訂ありがとうございます。ハイライトのことを知らなかった、私は物事が大丈夫に見えなかったときだけバッククォートを使用した。 – Rodolfo

1

たいのかわからパラメータは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テーブルを照会することができますクエリ内のテーブル名。もちろん、上記は誇張された例です。

-2

正しい構文(開始気づく):ここで

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

これはSQL Serverでは動作しません。動的SQLを使用する必要があります。@ BiggsTRCの答えを参照してください。そして、あなたは 'BEGIN'を必要としません –

+1

あなたは正しいです、私は速く私の答えを投稿したと思います –

+0

。 – AndrewBay

関連する問題