可能であれば、これを行わないでください。
それが答えです—それはアンチパターンです。クライアントがデータを必要とするテーブルを知っている場合は、SELECT FROM ThatTable
。これが必要とされる方法でデータベースが設計されている場合、データベースは最適に設計されていないようです。データアクセス層が値がテーブルに存在するかどうかを知る必要がある場合、そのコードでSQLを作成するのは簡単であり、このコードをデータベースにプッシュするのはよくありません。
私には、これは、希望する階数を入力できるエレベータ内にデバイスを設置するように思えます。Goボタンを押すと、機械式ハンドが目的のフロアの正しいボタンに移動して押されます。これにより、多くの潜在的な問題が発生します。
注意:ここでは、嘲笑の意図はありません。私のばかげたエレベーターの例は、このテクニックの問題を簡潔に指摘するための*私が想像できる最高のデバイス*でした。これは、間接参照の役に立たないレイヤーを追加し、テーブル名の選択を呼び出し元スペースから(堅牢でよく理解されているDSL、SQLを使用して)、あいまいで奇妙なサーバー側SQLコードを使用するハイブリッドに移動します。
クエリ構築ロジックを動的SQLに移行することで責任を分割すると、コードが理解しにくくなります。これは、エラーの可能性があるカスタムコードの名前で、標準の信頼できる規則(SQLクエリが選択するものを選択する方法)に違反しています。
このアプローチの潜在的な問題のいくつかに関する詳細なポイントは次のとおりです。
動的SQLは、フロントエンドコードまたはバックエンドコードだけでは認識しにくいSQLインジェクションの可能性を提供します(これを確認するには、それらを一緒に検査する必要があります)。
ストアドプロシージャと関数は、SP /関数の所有者が権利を持っているが、呼び出し元は持っていないリソースにアクセスできます。私が理解している限り、特別な注意を払わずに、動的SQLを生成して実行するコードをデフォルトで使用すると、データベースは呼び出し元の権限で動的SQLを実行します。つまり、特権オブジェクトをまったく使用できないか、すべてのクライアントに公開する必要があり、特権データへの潜在的な攻撃の表面積が増加します。作成時にSP /関数を常に特定のユーザー(SQL ServerでEXECUTE AS
)として実行するように設定すると、その問題は解決する場合がありますが、事態はさらに複雑になります。これは、動的SQLを非常に魅力的な攻撃ベクトルにすることにより、前のポイントで述べたSQLインジェクションのリスクを悪化させます。
開発者がアプリケーションコードを変更したりバグを修正したりするためにアプリケーションコードが何をしているのかを理解する必要がある場合、実行されている正確なSQLクエリを取得するのは非常に困難です。SQLプロファイラーを使用できますが、これには特別な特権が必要であり、実稼働システムのパフォーマンスに悪影響を与える可能性があります。実行されたクエリはSPによってログに記録できますが、これは疑わしい利点(新しいテーブルの収容、古いデータのパージなど)のために複雑さを増し、まったく自明ではありません。実際、一部のアプリケーションは、開発者がデータベースの資格情報を持たないように設計されているため、送信されているクエリを実際に確認することはほとんど不可能になります。
存在しないテーブルを選択しようとした場合など、エラーが発生すると、データベースから「無効なオブジェクト名」の行に沿ってメッセージが表示されます。これは、バックエンドでSQLを作成する場合でもデータベースで作成する場合でもまったく同じように発生しますが、違いは、システムのトラブルシューティングを試みている一部の貧しい開発者は、1つのレベルをさらに深く掘り下げて、問題が存在します。問題が何であるかを理解しようとするために、すべてを行うという不思議な手順を掘り下げます。ログには「GetWidgetのエラー」は表示されず、「OneProcedureToRuleThemAllRunnerのエラー」が表示されます。この抽象化は一般的にシステムを悪化させます。
パラメータに基づいてテーブル名を切り替える疑似C#の例:
string sql = $"SELECT * FROM {EscapeSqlIdentifier(tableName)};"
results = connection.Execute(sql);
これにより、考えられるすべての問題が解消されるわけではありませんが、他の手法で概説した欠陥は、この例にはありません。