SQLサブクエリを結合に、またはその逆に変換するための一般化された手順またはアルゴリズムはありますか?つまり、サブクエリを含まない機能的に同等のステートメントになるサブクエリを含む構文的に正しいSQLクエリステートメントに適用できる一連の活版印刷操作はありますか?もしそうなら、それらは何ですか(つまり、アルゴリズムは何ですか)、そしてどのような場合にそれらは適用されませんか?
7 に答える
サブクエリを JOIN に変換するのは非常に簡単です。
IN
句
FROM TABLE_X x
WHERE x.col IN (SELECT y.col FROM TABLE_Y y)
...次のように変換できます:
FROM TABLE_X x
JOIN TABLE_Y y ON y.col = x.col
JOIN 基準は、直接比較できる場所です。
EXISTS
句
EXISTS
しかし、条項を見ると複雑な点があります。通常、 EXISTSは相関関係にあり、サブクエリはサブクエリの外部のテーブルからの基準によってフィルター処理されます。ただし、 EXISTS は、基準に基づいてブール値を返すためだけのものです。
FROM TABLE_X x
WHERE EXISTS (SELECT NULL
FROM TABLE_Y y
WHERE y.col = x.col)
...変換された:
FROM TABLE_X x
JOIN TABLE_Y y ON y.col = x.col
ブール値のため、結果セットにさらに多くの行が表示されるリスクがあります。
SELECT
SELECT 句内の
これらは、偏見を持って常に変更する必要があります。
SELECT x.*,
(SELECT MAX(y.example_col)
FROM TABLE_Y y
WHERE y.col = x.col)
FROM TABLE_X x
おそらくパターンに気付いていると思いますが、インライン ビューの例ではこれを少し変えました。
SELECT x.*,
z.mc
FROM TABLE_X x
JOIN (SELECT y.col, --inline view within the brackets
MAX(y.example_col) 'mc'
FROM TABLE_Y y
GROUP BY y.col) z ON z.col = x.col
重要なのは、インライン ビューの結果セットに、結合に必要な列と列が含まれていることを確認することです。
LEFT JOIN
s
LEFT JOIN の例がないことに気付いたかもしれません。これは、サブクエリの列が NULL テストを使用する場合にのみ必要です (COALESCE
最近のほぼすべてのデータベース、Oracle のNVL
or NVL2
、MySQLs IFNULL
、SQL Server のISNULL
など...)。
SELECT x.*,
COALESCE((SELECT MAX(y.example_col)
FROM TABLE_Y y
WHERE y.col = x.col), 0)
FROM TABLE_X x
変換された:
SELECT x.*,
COALESCE(z.mc, 0)
FROM TABLE_X x
LEFT JOIN (SELECT y.col,
MAX(y.example_col) 'mc'
FROM TABLE_Y y
GROUP BY y.col) z ON z.col = x.col
結論
それがあなたのタイポグラフィのニーズを満たすかどうかはわかりませんが、重要なのは JOIN 基準が何であるかを決定することであることを実証したことを願っています. 関連する列がわかれば、関連するテーブルもわかります。
この質問は、リレーショナル代数の基本的な知識に依存しています。どのような種類の結合が実行されているかを自問する必要があります。たとえば、LEFT ANTI SEMI JOIN は WHERE NOT EXISTS 句に似ています。
データの複製を許可しない結合もあれば、データの削除を許可しない結合もあります。また、追加のフィールドを使用できるようにするものもあります。これについては、 http://msmvps.com/blogs/robfarley/archive/2008/11/09/join-simplification-in-sql-server.aspxのブログで説明しています。
また、JOIN ですべてを行う必要があるとは思わないでください。クエリ オプティマイザーはこれらすべてを処理する必要があり、多くの場合、この方法でクエリを維持するのがはるかに難しくなります。広範な GROUP BY 句を使用し、興味深い WHERE .. IS NULL フィルターを使用していることに気付くかもしれません。これは、ビジネス ロジックをクエリ デザインから切り離すだけの役割を果たします。
SELECT 句のサブクエリ (本質的にルックアップ) は、重複や削除ではなく、追加のフィールドを提供するだけです。したがって、JOIN で GROUP BY または DISTINCT 値を適用し、OUTER JOIN を使用して動作が同じであることを確認する必要があります。
WHERE 句のサブクエリはデータを複製したり、SELECT 句に余分な列を提供したりできないため、GROUP BY / DISTINCT を使用してこれを確認する必要があります。WHERE EXISTS も同様です。(これが LEFT SEMI JOIN です)
WHERE NOT EXISTS (LEFT ANTI SEMI JOIN) はデータを提供せず、行を複製しませんが、削除できます...このためには、LEFT JOIN を実行して NULL を探す必要があります。
ただし、クエリ オプティマイザーはこれらすべてを処理する必要があります。行を複製したり削除したりしていないことが非常に明確になるため、実際には SELECT 句で時々サブクエリを使用するのが好きです。QO で整理できますが、ビューまたはインライン テーブル値関数を使用している場合は、QO を使用すると大幅に簡素化できることを後に続く人に明確にしたいと思います。元のクエリの実行プランを見ると、システムが INNER/OUTER/SEMI 結合を提供していることがわかります。
(少なくとも SQL Server では) 本当に避ける必要があるのは、BEGIN と END を使用する関数 (スカラー関数など) です。コードを単純化しているように見えるかもしれませんが、システムはそれらを手続き型 (単純化できない) と見なすため、実際には別のコンテキストで実行されます。
最近のSQLBits Vカンファレンスで、この種のセッションを行いました。録画したので、いつか見られるはずです(私の冗談が我慢できれば!)
多くの場合、それは可能です。クエリ オプティマイザが自動的に実行できるので、気にする必要はありません。
本当に高いレベルで。サブクエリをJOINに変換するには:
- FROM:テーブル名はFROMに入ります
- JOIN両側にテーブル名があるWHERE句の部分によって、(a)JOINのタイプ(b)結合の条件が決まります。
- WHERE両側にテーブル名がないwhere句の部分は、WHERE句に入ります。
- サブクエリからのSELECT列名はSELECTに入ります
JOINをサブクエリに変換するには、上記のロジックの逆が必要です。
少なくとも SQL Server では、オプティマイザーがこれを自由に実行できますが、いつ実行するかについては制約があると確信しています。コンピューターでできるようになるのは、おそらく誰かの博士論文だったと思います。
私が昔ながらの人間のやり方でそれを行うとき、それはかなり簡単です - 特にサブクエリがすでにエイリアス化されている場合 - 最初に共通テーブル式に引き込むことができます。
これは、「場合による」と強く評価しています。
あるレベルでは、ANSI SQL 89 または 92* と互換性のあるクエリについて話しているのであれば、おそらく間違いないと思います。「基本的な」select、from、およびwhere句で構成される単純な(またはそれほど単純ではない)クエリがある場合、はい、サブクエリを作成および「作成解除」するプロセスと手順を定義することは数学的に可能であると思います(ただし、サブクエリをアルゴリズムで作成するタイミングをどのように判断するかは、私にはわかりません)。この「理論的根拠」は、外部結合と相関サブクエリに適用できると思います。
別のレベルでは、「まさか」と言うでしょう。ほとんどの場合、サブクエリを作成しますが、それは、サブクエリを「メイン」クエリに組み込む方法が思いつかないためです。これに相関サブクエリが含まれることはめったにありませんが、ほとんどの場合、標準に対する独自の拡張機能が含まれます。ピボット、アンピボット、ランキング関数、TOP N 句 (ANSI 標準である可能性が高いため、最初から最後まで読んだことがないことを認めます)、FULL または OUTER APPLY などをどのように説明できますか? これは SQL Server の一部にすぎません。Oracle、DB2、MYSQL、およびその他のほとんどすべてのプレーヤーが、「純粋主義」のリレーショナル モデルを打ち破る独自の拡張機能を持っていると確信しています。
もちろん、彼らは否定を証明することは不可能だと言います。私は「別の方法で証明されるまでは実行できない」と要約し、学者や理論家に証明を任せます。その場合でも、製造業者が財政的に合理的でない限り、購入するシステムがそれをサポートしないことを指摘します。 (OUTER UNIONをサポートしているシステムはありますか?)
** 少しグーグルで検索しても、3 番目の ANSI SQL 標準への参照を生成できませんでした。何年も前にその話を聞いたことがありますが、実際に起こったことはありますか? *
クエリをサブクエリから結合に変換するための完全に自動化されたシステムを構築するのは比較的困難です。入力クエリを取得し、それを解析して解析ツリーにし、解析ツリーでかなり複雑なパターン マッチを実行する必要があります。つまり、ツリーのセクションを解析ツリーの新しいセクションに置き換えます。最後に、ツリーを走査して新しいクエリを出力します。
There can be some amazingly good or bad performance repercussions. Sometimes a sub-query is much faster than a join. Sometimes it is the inverse.