[英]MySQL Query AND IN (select… - Need assistance in clarifying and is it a Sub Routine
您能否讓我知道我的解釋是否正確(最后一個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字段)等於registrar_id(field)的任何匹配項,其中industry_id等於集合$ industryid
由於它是主查詢中的查詢,因此該select語句是否被視為子例程?
因此,將注冊表ID搜索為23的示例如下所示:
注冊 (表)
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的返回值。
對於給定的測試數據集,您的查詢將返回一條記錄。 這個: id=23,title=owner,name=mike,company=nono,address1=1234 s walker lane,address2
要獲得具有相同注冊表數據和不同registrations_industry的三個記錄,您需要使用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}
對不起這篇文章,直到現在才看,我才意識到它才這么長。 而且,盡管您已經檢查了答案,但我希望您閱讀此書后能了解為什么首選此解決方案以及它是如何從原始查詢中演變而來的。
您的查詢
$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)
您可以通過引入子查詢來使其復雜一點,這沒問題。 只要您的子查詢返回一列(您的子查詢也是如此),則將其傳遞給IN
就可以了。
就您而言,您正在將registrations.id
與registrations_industry.registrar_id
進行比較。 (注意:這只是<table>.<field>
語法,沒什么特別的,但是有助於消除字段所在的表的歧義。)
這似乎很好。
SQL將首先運行子查詢,並生成registrar_id
的結果集,其中按指定的方式設置了industry_id
。
然后,SQL將運行外部查詢,用其結果替換子查詢,您將從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'
通過將r
和ri
放在FROM
子句中的兩個表之后,我們可以使用這些快捷方式引用它們。 這樣可以清理查詢,但仍然使我們能夠清楚地指定字段來自哪個表。
旁注:通過包括可選的AS
例如FROM registrations
AS
r
而不僅僅是FROM registrations r
,我們可以更清楚地了解表別名,但是我通常為字段別名保留AS
。
如果現在運行查詢,您將獲得所謂的“笛卡爾積”或SQL術語中的CROSS JOIN
。 這是因為實際上,在兩個表之間沒有任何關系時,我們沒有定義任何關系。 為了解決這個問題,我們需要重新引入丟失的原始查詢的一部分:兩個表之間的關系
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
表,但不使用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
和OR
子句可以自由表達任何限制。 另一種看待這種情況的方式是,如果您刪除了WHERE + AND/OR
子句,則表之間的關系仍將保持,結果仍將“有意義”,而如果您使用隱式方法並刪除了WHERE + AND/OR
子句,您的結果集將包含誤導的行。
最后, JOIN
本身的語法將導致在行registrations
,但沒有任何相應的行registrations_industry
不退還。
根據您的用例,您可能希望registrations
行出現在結果中,即使registrations_industry
中沒有相應的條目。 為此,您將使用OUTER JOIN
。 在這種情況下,我們需要所謂的LEFT OUTER JOIN
因為我們希望表的所有行都在左側( registrations
)。 我們可以選擇將RIGHT OUTER JOIN
用於右表,或者僅將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'
我們完成了。
最終結果是我們有一個查詢
此查詢的簡單版本為:
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表中提取數據,因為從技術上講,它不是聯接的,並且該子表也不是父查詢的一部分。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.