簡體   English   中英

MySQL查詢和輸入(選擇…-需要幫助進行澄清,它是否是子例程

[英]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.idregistrations_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'

通過將rri放在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

結果將是相同的,但它使用正確的(更清晰的)語法。 (它更清楚,因為它明確指出foobar表之間存在關系,並且由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以及后續的ANDOR子句可以自由表達任何限制。 另一種看待這種情況的方式是,如果您刪除了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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM