私を許して、私はSQLの世界に移動した開発者です。変数を追加していくつかのSQLを改善できると思いましたが、期待したように機能しませんでした。なぜこれがうまくいかないのか誰かに教えてもらえますか?私は回避策を望んでいません。これは、正当な理由があると確信しているので、私が想像するようにこれが機能しない理由を知りたいのですが、現在、私には飛び出しません。
DECLARE @DatabaseName varchar(150)
SET @DatabaseName = 'MyAmazingDatabaseName'
CREATE DATABASE @DatabaseName
GO
USE @DatabaseName
GO
変数 のBooksオンラインページごと
変数は式でのみ使用でき、オブジェクト名やキーワードの代わりには使用できません。動的SQLステートメントを作成するには、EXECUTEを使用します。
これは、たとえば、where句で変数を使用した場合に期待したとおりに機能します。理由については、パーサーが変数を評価できず、存在を確認できないことに関係していると思います。クエリを実行すると、まず構文とオブジェクトについてクエリが解析され、次に解析が成功した場合、クエリが実行され、その時点で変数が設定されます。
DECLARE @name varchar(20);
SET @name = 'test';
CREATE TABLE [#tmp]([val] varchar(10));
insert into #tmp
values('test')
SELECT *
FROM [#tmp]
WHERE [val] = @name;
SQLステートメントでの変数の使用に関する制限は、SQLのアーキテクチャーから生じます。
SQLステートメントの処理には3つのフェーズがあります。
SQLサーバーは準備段階をプログラマーから隠し、OracleやDB2などの従来のデータベースよりもはるかに高速に実行します。 SQLが最適な実行計画を決定するのに潜在的に多くの時間を費やすのはパフォーマンス上の理由からですが、再起動後に初めてステートメントが検出されたときだけです。
したがって、静的SQLでは、変数は実行プランを無効にしない場所でのみ使用できます。テーブル名、列名(WHERE条件の列名を含む)などでは使用できません。
動的SQLは、制限を回避できない場合に存在し、プログラマは実行に少し時間がかかることを知っています。動的SQLは悪意のあるコードインジェクションに対して脆弱になる可能性があるため、注意してください!
ご覧のとおり、「なぜ」の質問には、言語の歴史的根拠や根本的な仮定など、さまざまな種類の回答が必要です。その正義が本当にできるかどうかはわかりません。
SQL MVP Erland Sommarskogによるこの包括的な記事は、メカニズムとともにいくつかの理論的根拠を提供しようとしています。
クエリプランのキャッシュ
SQL Serverで実行するすべてのクエリには、クエリプランが必要です。クエリを初めて実行すると、SQL Serverはクエリのクエリプランを作成します(用語が進むにつれて)、クエリをコンパイルします。 SQL Serverはプランをキャッシュに保存し、次にクエリを実行すると、プランが再利用されます。
これ(およびセキュリティ、以下を参照)がおそらく最大の理由です。
SQLは、クエリが1回限りの操作ではなく、何度も使用されるという前提の下で動作します。テーブル(またはデータベース!)がクエリで実際に指定されていない場合、将来使用するために実行プランを生成して保存する方法はありません。
はい、実行するすべてのクエリが再利用されるわけではありませんが、これはSQLのデフォルトの動作前提であるため、「例外」は例外的なものです。
Erlandがリストする他のいくつかの理由(ストアドプロシージャを使用する利点を明示的に示していることに注意してください。ただし、これらの多くはパラメーター化(非動的)クエリの利点でもあります)
繰り返しますが、これらにはそれぞれ、ここでは触れない100のニュアンスがあります。
動的SQLを使用する必要があります
DECLARE @DatabaseName varchar(150) = 'dbamaint'
declare @sqltext nvarchar(max) = N''
set @sqltext = N'CREATE DATABASE '+quotename(@DatabaseName)+ ';'
print @sqltext
-- once you are happy .. uncomment below
--exec sp_executesql @sqltext
set @sqltext = ''
set @sqltext = N'use '+quotename(@DatabaseName)+ ';'
print @sqltext
-- once you are happy .. uncomment below
--exec sp_executesql @sqltext
以下はprintの出力です.. exec sp_executesql @sqltext
のコメントを解除すると、ステートメントが実際に実行されます...
CREATE DATABASE [dbamaint];
use [dbamaint];