2015-08-17 42 views
2

我期待多行:的MySQL(ERROR子查詢返回多個1行) - 但我期待超過1列

SELECT * FROM OWNER 

    WHERE OWNER.ID IN(
      (
      SELECT 
       ID 
      FROM OWNER 
      WHERE 
       LAST_NAME LIKE '%pickles%' 
       OR FIRST_NAME LIKE '%pickles%' 
      ), 

      (
      SELECT 
       OWNER_ID 
      FROM VISITOR 
      WHERE 
       NAME LIKE '%pickles%' 
       OR SIZE LIKE '%pickles%' 
      ), 

      (
      SELECT 
       OWNER_ID 
      FROM BOARDING 
      WHERE 
       COMMENTS LIKE '%pickles%' 
       OR PERSONAL_BELONGINGS LIKE '%pickles%' 
      ) 

     ) 

第二個子查詢

FROM VISITOR 
     WHERE 
      NAME LIKE '%pickles%' 

導致錯誤。 但我期待多行返回? 它應該從找到的行中返回一些ID。 那麼爲什麼這些多行有問題呢?

謝謝。

回答

2

我認爲你正在尋找一個union

SELECT * FROM OWNER 
WHERE OWNER.ID IN(

     SELECT ID 
     FROM OWNER 
     WHERE LAST_NAME LIKE '%pickles%' 
      OR FIRST_NAME LIKE '%pickles%' 

     UNION 

     SELECT OWNER_ID 
     FROM VISITOR 
     WHERE NAME LIKE '%pickles%' 
      OR SIZE LIKE '%pickles%' 

     UNION 

     SELECT OWNER_ID 
     FROM BOARDING 
     WHERE COMMENTS LIKE '%pickles%' 
      OR PERSONAL_BELONGINGS LIKE '%pickles%' 


    ) 

說明:

你的子查詢返回的結果中3分,如:

​​

使用UNION ,它將返回如下形式:

ID 
------------------- 
OWNER_table_ids 
Visitor_table_ids 
Boarding_table_ids 

錯誤「子查詢返回多個值」僅表示「超過1列」。

+0

非常感謝您@Raging公牛。 我認爲個人選擇將結合身份證。 爲什麼多個ID會被視爲錯誤? 它試圖說它發現重複? – Kreeverp

+1

@Kreeverp:當您使用'IN'運算符時,子查詢必須只返回1列來查找。使用您的查詢,它將返回3列。這就是錯誤所說的。子查詢返回的值超過1意味着「超過1列」。 –

+0

有點令人困惑,錯誤報告「行」而不是列? – Kreeverp

0

接受的答案確實提供了一個工作解決方案,但是爲什麼現有查詢不能像寫入那樣正確解釋。

存在多種類型的子查詢,返回多種類型的結果。

在您的查詢:

WHERE expr IN ((/* subq 1 */), (/* subq 2 */), (/* subq 3 */)) 

...等價於...

WHERE expr = (/* subq 1 */) 
    OR expr = (/* subq 2 */) 
    OR expr = (/* subq 3 */) 

這是,也只能是三相等比較。以這種方式使用子查詢將一定可以在標量上下文...解釋和標量子查詢只能返回一行或零行,因爲子查詢的結果將被用作scalar operand。對於服務器來解釋它否則是不合邏輯的:你能比較一個值與兩個值還是更多,並進行相等比較?如果您的查詢不是,請求服務器從子查詢中構建所有結果的集合,然後測試OWNER.ID是否設置爲IN()。您的查詢要求服務器構建一個包含最多三個標量值(每個子查詢一個)的集合,並確定OWNER.ID是否爲IN()(可能小得多)集合。這些子查詢中的任何一個返回多於一行的事實使查詢無效。你很幸運,它已經不起作用了。如果您選擇的數據只匹配一行,現在就可以奏效,但是當您有更多的匹配項時,這些數據就會分崩離析。

ERROR 1242 (21000): Subquery returns more than 1 row 

如果(人工)加入LIMIT 1到三個子查詢中,你會發現,該查詢實際上做的工作,這說明我的觀點。結果將不完整,但查詢是有效的,這反駁了錯誤是關於「列」的斷言。這是一組......但是,正如所寫,它是,而且只能是一組標量。

重構與UNION澄清你的意圖到服務器。

注意,如果斷言誤差約爲列是正確的,該消息會有所不同:

ERROR 1241 (21000): Operand should contain 1 column(s) 

現在,已經解釋了錯誤的實際原因,我也會扔在一個備用解。如果您尚未擁有VISITOR和BOARDING中的(OWNER_ID),您應該有一個索引。此解決方案與UNION解決方案之間的性能可能會因各種表中的數據組成以及MySQL服務器的版本而異。這兩種解決方案都不是最佳選擇,因爲LIKE比較中的起始%需要表或至少一個包含該列的索引(如果有的話)被完整讀取。這是全表掃描或全索引掃描,「掃描」是指逐行。結局%沒問題;開始%是昂貴的,因爲它從列的左手邊取消固定模式,這是索引工作的地方。如果可以的話,應用程序允許的情況下將其刪除,以獲得更好的性能,並對搜索列進行索引;如果你不能刪除領先的%,至少要明白這是你將會看到的性能的貢獻者。這是B-Tree索引的一般限制,而不是MySQL。你最終也可能想看看FULLTEXT search

SELECT o.* 
    FROM OWNER o 
WHERE o.LAST_NAME LIKE '%pickles%' 
    OR o.FIRST_NAME LIKE '%pickles%' 
    OR EXISTS(SELECT * 
       FROM VISITOR v 
       WHERE v.OWNER_ID = o.ID 
       AND (v.NAME LIKE '%pickles%' OR v.SIZE LIKE '%pickles%') 
      ) 
    OR EXISTS(SELECT * 
       FROM BOARDING b 
       WHERE b.OWNER_ID = o.ID 
       AND (COMMENTS LIKE '%pickles%' OR PERSONAL_BELONGINGS LIKE '%pickles%') 
      ); 

請注意,EXISTS(SELECT * ...)yet another form of subquery, entirely different than anything we've considered so far。特別值得注意的是*只是一個慣例。您可以說SELECT 1SELECT TRUE,並沒有關係,因爲沒有數據實際上被選中,並且EXISTS()沒有任何數據被返回,TRUE除外 - 子查詢匹配目標表中的一行或更多行 - 或FALSE - 它沒有。請注意,這些查詢引用外部查詢o.ID中的值,因此它們在此處我們檢查所有者表以查找匹配條件,然後在必要時檢查行中是否存在行訪客或登機以獲得匹配標準。如果名爲「Cat」的女性有一隻名爲「Cat」的狗,並且您在尋找「Cat」,那麼我們會在OWNER中找到它,優化程序可能會避免爲該用戶搜索其他兩張表,因爲我們已經知道她是一場比賽,無論出於何種原因。

參見:https://dev.mysql.com/doc/refman/5.6/en/subquery-errors.html