0

私の解釈が正しいかどうか教えていただけますか(最後のAND部分)?

$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'
      )";

以下は本当に私が確信していないところです:

... AND id IN (select registrar_id from registrations_industry where industry_id='$industryid')

解釈: 結合テーブルregistrations_industryからid(registrations id field)がregistrar_id(field)と等しい場合に一致するものを取得します。ここで、industry_idはセット$industryidと等しくなります。

このselectステートメントはメインクエリ内のクエリであるため、サブルーチンと見なされますか?

したがって、例として、23へのレジスタテーブルID検索は次のようになります。

登録(表)

id=23,title=owner,name=mike,company=nono,address1=1234 s walker lane,address2

Registrations_industry(テーブル)

id=256, registrar_id=23, industry_id=400<br>
id=159, registrar_id=23, industry_id=284<br>
id=227, registrar_id=23, industry_id=357

これにより、同じ登録テーブルデータを持つ3つのレコードが返されると思います。もちろん、registrations_industryが返されます。

4

3 に答える 3

2

特定のテスト データ セットに対して、クエリは 1 つのレコードを返します。これ: id=23,title=owner,name=mike,company=nono,address1=1234 s walker lane,address2
登録テーブルのデータが同じで、registrations_industry が異なる 3 つのレコードを取得するには、 を使用する必要がありますJOIN

このようなもの:

SELECT r.title, r.name, r.company, r.address1, r.address2 
FROM registrations AS r
LEFT OUTER JOIN registrations_industry AS ri
ON ri.registrar_id=r.id
WHERE r.title!=0 AND ri.industry_id={$industry_id}
于 2012-06-26T22:04:10.123 に答える
2

エッセイですみません、今見るまでこんなに長いとは思いませんでした。回答を確認しましたが、これを読んで、このソリューションが好まれる理由と、元のクエリからどのように進化したかについての洞察を得ていただければ幸いです。

まず最初に

クエリ

$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.idregistrar_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との後に配置することで、これらのショートカットを使用してそれらを参照できます。これにより、クエリがクリーンアップされますが、フィールドがどのテーブルから取得されているかを明確に指定することができます。riFROM

補足:単なる ではなくASegを含めることで、テーブル エイリアスについてより明確にすることができますが、通常はフィールド エイリアス用に予約します。FROM registrationsASrFROM registrations rAS

ここでクエリを実行すると、いわゆる「デカルト積」または 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節に含まれるようになったため、WHEREand に続くANDandOR節は自由に制限を表現できます。これを見る別の方法は、句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'

これで完了です。

最終結果は、次のクエリがあります。

  • 実行時間の点でより高速
  • よりコンパクト/簡潔
  • フィールドがどのテーブルから来ているかについてより明確に
  • テーブル間の関係についてより明確に
于 2012-06-26T22:41:07.733 に答える
0

このクエリのより単純なバージョンは次のようになります。

SELECT title,  name, company, address1, address2
  FROM registrations, registrations_industry
 WHERE title != 0
   AND id = registrar_id
   AND industry_id = '$industryid'

お使いのバージョンはサブクエリでした。このバージョンは単純な結合です。クエリに関するあなたの仮定は一般的に正しいですが、SQLが最適化するのは難しく、コードを読み込もうとしている人に解明するのは少し難しいです。また、その親SELECTステートメントのregistrations_industryテーブルからデータを抽出することはできません。これは、データが技術的に結合されておらず、サブテーブルが親クエリの一部ではないためです。

于 2012-06-26T22:00:37.170 に答える