Dynamics GPを実行します。GPを扱っている人なら誰でも、アプリケーション内のさまざまな列挙値を表すその「マジックナンバー」列のすべてに精通しています。たとえば、レポートクエリは次のようになります。
...
WHERE sod.SOPTYPE = 2
AND iv.VCTNMTHD = 3
AND pod.POLNESTA IN (2, 3)
...これは、自己文書化から可能な限り離れています。
最初は「Enums」というテーブルを作成して値を入力し、スカラーラッパー関数を作成して次のようにクエリできるようにするという明るいアイデアを思いつきました。
...
WHERE sod.SOPTYPE = Enum('Sales Doc Type', 'Order')
AND iv.VCTNMTHD = Enum('Valuation Method', 'Average Perpetual')
AND pod.POLNESTA IN (Enum('PO Line State', 'Released'), Enum('PO Line State', 'Change Order'))
もちろん、オプティマイザは基礎となる「定数」値を認識できず、カーディナリティを推測する必要があったため、かなり貧弱な選択を行ったため、それは失敗しました。
したがって、コードでは実際の定数値である必要がありますが、この種のことを簡単にするSSMSに組み込まれたNice機能があるかどうかはわかりません。コードスニペットまたはテンプレートを何らかの方法で(誤用)できますか?なんらかのルックアップ/挿入を実行してコードを次のようにすることができれば、それはすばらしいことです。
...
WHERE sod.SOPTYPE = /*Order*/2
AND iv.VCTNMTHD = /*Average Perpetual*/3
AND pod.POLNESTA IN (/*Released*/2, /*Change Order*/3)
また、SSMSアドインのチェックアウトにも反対していません。
このルックアップをSSMS/SQLCMD固有の機能にanyの方法で結び付けないようにすることを実際にお勧めします。そのためには、コードがこれら2つのプログラムだけを使用してのみ実行できることが必要です。 SSMSまたはSQLCMDから実行されたとしても、そのようなロジックをストアドプロシージャに組み込むことはできません。また、SSRSなどでSQLCMDコマンドを使用することもできません。
一部のオプション(それらを実行するために使用されるクライアントツールから完全に独立しています):
SQL Server 2019がオプションである場合、新しい Scalar UDF Inlining 機能がEnum('Sales Doc Type', 'Order')
アプローチの問題を解決する可能性があります。
インラインTVFがうまくいく可能性があります。 WHERE
句のこれらの述語をINNER JOIN
sになるように再構築する必要がある場合があります。
FROM SOPxxxxx sod
INNER JOIN dbo.Enum('Sales Doc Type', 'Order') sdt
ON sod.SOPTYPE = sdt.Value
もちろん、IN
リストは少しトリッキーです。これは、各オプションにLEFT JOIN
が必要で、次にWHERE
述語が必要になる可能性があるためです。 NULL
:
FROM dbo.POP10110 pod
LEFT JOIN dbo.Enum('PO Line State', 'Released') pls_r
ON pod.POLNESTA = pls_r.Value
LEFT JOIN dbo.Enum('PO Line State', 'Change Order') pls_co
ON pod.POLNESTA = pls_co.Value
WHERE ( pls_r.Value IS NOT NULL
OR pls_co.Value IS NOT NULL)
[〜#〜]または[〜#〜]、これと同じiTVFを使用すると、より読みやすく管理しやすい非相関サブクエリを実行できる場合があります。
FROM SOPxxxxx sod
WHERE sod.SOPTYPE = (SELECT sdt.Value FROM dbo.Enum('Sales Doc Type', 'Order') sdt)
そしてIN
リストは少なくとも見栄えが良いです:
FROM dbo.POP10110 pod
WHERE pod.POLNESTA IN (
SELECT pls_r.Value
FROM dbo.Enum('PO Line State', 'Released') pls_r
UNION ALL
SELECT pls_co.Value
FROM dbo.Enum('PO Line State', 'Change Order') pls_co
)
または、おそらく(クエリオプティマイザが何を好むかわからない):
FROM dbo.POP10110 pod
WHERE pod.POLNESTA IN (
(SELECT pls_r.Value FROM dbo.Enum('PO Line State', 'Released') pls_r),
(SELECT pls_co.Value FROM dbo.Enum('PO Line State', 'Change Order') pls_co)
)
SQLCLRがオプションの場合、notがデータにアクセスするandを実行するSQLCLRスカラーUDFは、[SqlFunction(IsDeterministic = true)]
としてマークされ、実行計画に定数で折りたたまれます( 「クエリ処理アーキテクチャガイド」のドキュメントには現在、SQLCLR関数を折りたたむことはできないと記載されていますが、これは間違いである可能性があるため、SQL Server 2012でその機能が追加されたときにドキュメントが更新されなかったのではないかと思います。 「クエリ処理アーキテクチャガイド」の「定数の折りたたみ」情報を修正 )。
ここでの秘訣は、SQLCLRスカラーUDFでデータを読み取ることなくテーブルからデータを読み取ることです。これにより、データを折りたたみ可能にすることができます。これを行うには、次の手順を実行します。
SqlConnection
を使用してローカルインスタンスに接続するクラスの静的コンストラクターを作成します。これにより、テーブルから選択され、静的辞書が読み込まれます。このコンストラクタは、メモリの圧迫やDBCC FREESYSTEMCACHE
などによってアセンブリがアンロードされた場合でも、辞書が常に入力されるようにします。残念ながら、内部の「コンテキスト」接続は、SQLコンテキストがないためここでは使用できません。静的コンストラクターが実行されます(ただし、あったとしても素晴らしいでしょう!)。WITH PERMISSION_SET = EXTERNAL_ACCESS
のマークを付けます。辞書は「読み取り専用」であるため、UNSAFE
を指定する必要はありません。 「読み取り専用」であっても、アイテムの追加や削除が可能です。これは、すべてのユーザーに対して常に同じである使い捨てのコレクションであるため、問題を引き起こすことはありません。[SqlFunction(IsDeterministic = true)]
デフォルトでDataAccess
に設定されているため、SystemDataAccess
またはNone
プロパティを指定する必要はありません。このメソッドを使用すると、これまで実行していたEnum()
アプローチを実装できます。また、サードパーティのアプリを使用しているので、アセンブリを別のデータベースにインストールすることで、問題を "クリーン"に保つことができます(レポートのプロシージャなどでも同様です)。私はそれがまだ一定のフォールディングを行うことをテストして確認しました。
[〜#〜] or [〜#〜](これは本当にオプション3bです):これが3番目であることを考えるとパーティーアプリ。ルックアップ値/列挙値がほとんど変化しないと仮定しても安全である場合、テーブルからそれらを読み取る必要はありません。 .NETコードで辞書全体をハードコード化することができます。このアプローチでは、現在のインスタンスに外部SqlConnection
を戻す必要がないため、アセンブリをPERMISSION_SET = SAFE
としてマークしておくことができます。
SSMS内では、SQLCMDモードを有効にして、次のように実行できます。
-- Enable SQLCMD Mode (ALT+Q+M)
:SetVar cSomeNumber 42
SELECT $(cSomeNumber)
スクリプトをファイルに保存した場合、これらを使用した場合と同じように動作します。待機する... SQLCMD.exe
":SetVar"と "$(cSomeNumber)"は処理されますbeforeただし、SQLはエンジンに送信されます。つまり、これは別のクライアント(ADO.Netなど)では使用できず、DBOを作成すると、解釈された値が記録されます。したがって、この:
-- Enable SQL Command Mode (ALT+Q+M)
:SetVar cSomeNumber 42
CREATE View Test AS SELECT $(cSomeNumber) as SomeNumber
これが得られます:
-- Enable SQL Command Mode (ALT+Q+M)
CREATE View [dbo].[Test] AS SELECT 42 as SomeNumber
これは、すべてのユーティリティを制限します。