エッセイですみません、今見るまでこんなに長いとは思いませんでした。回答を確認しましたが、これを読んで、このソリューションが好まれる理由と、元のクエリからどのように進化したかについての洞察を得ていただければ幸いです。
まず最初に
クエリ
$q = "SELECT title,name,company,address1,address2
FROM registrations
WHERE title != 0 AND id IN (
SELECT registrar_id
FROM registrations_industry
WHERE industry_id = '$industryid'
)";
元気そうです。構文は、多数の一致IN
に相当します。OR
例えば
WHERE field_id IN (101,102,103,105)
機能的に同等です
WHERE (field_id = 101
OR field_id = 102
OR field_id = 103
OR field_id = 105)
サブクエリを導入することで少し複雑になりますが、問題ありません。サブクエリが 1 つの列を返す限り (そしてあなたの場合も)、それを に渡すことはIN
問題ありません。
あなたの場合、あなたは と比較registrations.id
していregistrations_industry.registrar_id
ます。(注: これは単なる<table>.<field>
構文であり、特別なことではありませんが、フィールドがどのテーブルにあるかを明確にするのに役立ちます。)
これは問題ないようです。
何が起こるのですか
SQL は最初にサブクエリを実行し、が指定どおりに設定されregistrar_id
た s の結果セットを生成industry_id
します。
次に、SQL は外側のクエリを実行し、サブクエリをその結果に置き換えます。サブクエリから返された s の 1 つに一致するregistrations
場所から行を取得します。registrations.id
registrar_id
サブクエリは、コードをデバッグするのに役立ちます。サブクエリを引き出して個別に実行し、期待どおりの出力を保証できるからです。
最適化
サブクエリはデバッグには適していますが、遅く、少なくとも最適化されたJOIN
ステートメントを使用するよりも遅くなります。
この場合、. を使用して、クエリを単一レベルのクエリ (サブクエリなし) に変換できますJOIN
。
まず、基本的にまったく同じ外部クエリから始めます。
SELECT title,name,company,address1,address2
FROM registrations
WHERE title != 0 AND ...
ただし、テーブルのデータにも関心がregistrations_industry
あるため、それを含める必要があります。私たちに与える
SELECT title,name,company,address1,address2
FROM registrations, registrations_industry
WHERE title != 0 AND ...
... を修正する必要があります。registrations_industry
テーブルができたので、次のことができます。
SELECT title,name,company,address1,address2
FROM registrations, registrations_industry
WHERE title != 0
AND id = registrar_id
AND industry_id = '$industryid'
id
両方のテーブルに列がある場合、問題が発生する可能性がありますid
。<table>.<field>
構文を使用して、これを明確にすることができます。のように
SELECT registrations.title, registrations.name,
registrations.company, registrations.address1, registrations.address2
FROM registrations, registrations_industry
WHERE registrations.title != 0
AND registrations_industry.industry_id = '$industryid'
すべてのフィールド参照にこの構文を使用する必要はありませんでしたが、わかりやすくするために選択しました。すべてのテーブル名が原因で、クエリが不必要に複雑になりました。あいまいさを解消して明確にしながら、それらを短くすることができます。これを行うには、テーブル エイリアスを作成します。
SELECT r.title, r.name, r.company, r.address1, r.address2
FROM registrations r, registrations_industry ri
WHERE r.title != 0
AND ri.industry_id = '$industryid'
句内の 2 つのテーブルをr
との後に配置することで、これらのショートカットを使用してそれらを参照できます。これにより、クエリがクリーンアップされますが、フィールドがどのテーブルから取得されているかを明確に指定することができます。ri
FROM
補足:単なる ではなくAS
egを含めることで、テーブル エイリアスについてより明確にすることができますが、通常はフィールド エイリアス用に予約します。FROM registrations
AS
r
FROM registrations r
AS
ここでクエリを実行すると、いわゆる「デカルト積」または SQL 用語でCROSS JOIN
. これは、実際には 1 つのテーブルがあるのに、2 つのテーブル間の関係を定義していないためです。これを修正するには、失われた元のクエリの一部を再導入する必要があります: 2 つのテーブル間の関係
r.id = ri.registrar_id
クエリは次のようになります
SELECT r.title, r.name, r.company, r.address1, r.address2
FROM registrations r, registrations_industry ri
WHERE r.title != 0
AND r.id = ri.registrar_id
AND ri.industry_id = '$industryid'
そして、これは完全に機能するはずです。
ちょっとしたこと -- 暗黙的な結合と明示的な結合
しかし、これは「暗黙の結合」と呼ばれることを指摘しておく必要があります。基本的に、テーブルを結合していますが、JOIN
構文は使用していません。
暗黙的な結合のより簡単な例は次のとおりです。
SELECT *
FROM foo f, bar b
WHERE f.id = b.foo_id
対応する明示的な構文は次のとおりです。
SELECT *
FROM foo f
JOIN bar b ON f.id = b.foo_id
結果は同じになりますが、適切な (そしてより明確な) 構文を使用しています。foo
(とbar
テーブルの間に関係があり、 によって定義されていることを明示的に示しているため、より明確ですf.id = b.foo_id
。)
同様に、暗黙のクエリを表現できます
SELECT r.title, r.name, r.company, r.address1, r.address2
FROM registrations r, registrations_industry ri
WHERE r.title != 0
AND r.id = ri.registrar_id
AND ri.industry_id = '$industryid'
明示的に次のように
SELECT r.title, r.name, r.company, r.address1, r.address2
FROM registrations r
JOIN registrations_industry ri ON r.id = ri.registrar_id
WHERE r.title != 0
AND ri.industry_id = '$industryid'
ご覧のとおり、テーブル間の関係がJOIN
節に含まれるようになったため、WHERE
and に続くAND
andOR
節は自由に制限を表現できます。これを見る別の方法は、句WHERE + AND/OR
を削除した場合、テーブル間の関係は引き続き保持され、結果は依然として「意味のある」ものになりますが、暗黙的な方法を使用してWHERE + AND/OR
句を削除した場合、結果セットには次の行が含まれます。誤解を招く。
最後に、JOIN
構文自体によって、 にあるが、registrations
に対応する行がregistrations_industry
ない行が返されなくなります。
registrations
ユース ケースによっては、 に対応するエントリがない場合でも、 の行を結果に表示したい場合がありますregistrations_industry
。これを行うには、 と呼ばれるものを使用しますOUTER JOIN
。この場合、LEFT OUTER JOIN
左側のテーブルのすべての行 ( registrations
) が必要なため、a と呼ばれるものが必要です。RIGHT OUTER JOIN
代わりに、右側のテーブルまたは単に両方のOUTER JOIN
テーブルの外部結合に使用することもできます。
したがって、クエリは次のようになります
SELECT r.title, r.name, r.company, r.address1, r.address2
FROM registrations r
LEFT OUTER JOIN registrations_industry ri ON r.id = ri.registrar_id
WHERE r.title != 0
AND ri.industry_id = '$industryid'
これで完了です。
最終結果は、次のクエリがあります。
- 実行時間の点でより高速
- よりコンパクト/簡潔
- フィールドがどのテーブルから来ているかについてより明確に
- テーブル間の関係についてより明確に