2009-02-09 50 views
17

我想通過指定innertable.id = outertable.id來爲內部查詢提供WHERE條件。但是,MySQL(5.0.45)在'where子句'「中報告」未知列'outertable.id'「。這種類型的查詢可能嗎?JOIN語法中的MySQL相關子查詢

內部查詢使用GROUP BY將行轉移到列。這可以完全在外部查詢中執行,但由於額外的連接可能會導致額外的開銷。

或者,我可以在內部查詢中省去WHERE條件,而是指定一個ON outertable.id = innerquery.id,但它會取出整個內部查詢行集再次連接到外部,這是低效的。

實際的SQL如下所示:

select t.ticketid, u.userid, t.fullname, u.loginapi_userid, t.email, tp.subject, tp.contents, a.PhoneNumber, a.Location, a.Extension, a.BusinessUnit, a.Department 
from swtickets t 
inner join swticketposts tp on t.ticketid = tp.ticketid 
inner join swusers u on t.userid = u.userid 
left join 
    (
    select 
    cfv.typeid, 
    min(case cfv.customfieldid when 1 then cfv.fieldvalue end) as 'PhoneNumber', 
    min(case cfv.customfieldid when 3 then cfv.fieldvalue end) as 'Location', 
    min(case cfv.customfieldid when 5 then cfv.fieldvalue end) as 'Extension', 
    min(case cfv.customfieldid when 8 then cfv.fieldvalue end) as 'BusinessUnit', 
    min(case cfv.customfieldid when 9 then cfv.fieldvalue end) as 'Department' 
    from swcustomfieldvalues cfv 
    where cfv.typeid = t.ticketid 
    group by cfv.typeid 
) as a on 1 = 1 
where t.ticketid = 2458; 
+2

我原來的問題是,「這種類型的查詢可能嗎?」 (相對於MySQL 5.0)。 更改模式或在應用程序代碼上進行分析不屬於問題主題。 – 2009-02-10 15:31:48

回答

29

您的問題的答案是否定的,不可能像您所做的那樣引用相關名稱。派生表由內部查詢在外部查詢開始評估連接之前生成。因此,相關名稱如t,tpu不適用於內部查詢。

爲了解決這個問題,我建議在內部查詢中使用相同的常量整數值,然後使用實際條件而不是1=1在外部查詢中連接派生表。

SELECT t.ticketid, u.userid, t.fullname, u.loginapi_userid, t.email, 
    tp.subject, tp.contents, a.PhoneNumber, a.Location, a.Extension, 
    a.BusinessUnit, a.Department 
FROM swtickets t 
INNER JOIN swticketposts tp ON (t.ticketid = tp.ticketid) 
INNER JOIN swusers u ON (t.userid = u.userid) 
LEFT OUTER JOIN (
    SELECT cfv.typeid, 
    MIN(CASE cfv.customfieldid WHEN 1 THEN cfv.fieldvalue END) AS 'PhoneNumber', 
    MIN(CASE cfv.customfieldid WHEN 3 THEN cfv.fieldvalue END) AS 'Location', 
    MIN(CASE cfv.customfieldid WHEN 5 THEN cfv.fieldvalue END) AS 'Extension', 
    MIN(CASE cfv.customfieldid WHEN 8 THEN cfv.fieldvalue END) AS 'BusinessUnit', 
    MIN(CASE cfv.customfieldid WHEN 9 THEN cfv.fieldvalue END) AS 'Department' 
    FROM swcustomfieldvalues cfv 
    WHERE cfv.typeid = 2458 
    GROUP BY cfv.typeid 
) AS a ON (a.typeid = t.ticketid) 
WHERE t.ticketid = 2458; 
0

我的建議將是你效率的理由排除了什麼。例如。刪除where子句並使用連接(按照t.ticketid = a.ticketid)

您是否能夠通過一些具體示例證明您對低效率的看法?我知道你在說什麼,但是無論你在外部查詢中使用每一行的方法是否被加入到內部查詢中的每一行中,所以根據執行計劃,它可能不像你懷疑的那樣低效。

0

我想象的問題是'cfv.typeid = t.ticketid'呢?我的想法是,儘管MySQL支持相關的子查詢,但你試圖做的事似乎可能會失敗,因爲「內部」查詢並不真正在查詢的其餘部分「內部」在WHERE子句中。但是看起來你可以從子查詢中取出where子句,並在a.typeid = t.ticketid上創建連接條件。

+0

對不起,這是查詢的另一個變體剩餘的。它與產生的實際錯誤沒有任何關係,所以我從上面的問題中刪除了它。 – 2009-02-09 23:13:18

1

我會寫多個連接。當你說它「可能會招致額外的開銷」時,告訴我你沒有測試它是肯定的。如果你有不錯的索引,聯接應該是非常平凡的。

這也顯示了通用的「容納所有」表格設計模式的一個缺陷。

+1

確實。該設計被稱爲實體屬性值。它以多種方式打破標準化,而且很難使用。 – 2009-02-10 02:57:09

+0

在內部查詢(cfv)中使用「WHERE cfv.typeid = 2458」會導致在cfv上進行令人討厭的表掃描,因爲缺少索引,但是,忽略此情況會導致更糟糕的情況,從而導致「Using temporary; Using filesort 「除了派生查詢上的附加表掃描。 – 2009-02-10 15:28:13

2

您正在使用Entity-Attribute-Value設計,如果您嘗試生成傳統結果集,最終無法使其具有可伸縮性。不要試圖在一個查詢中做到這一點。

相反,先查詢您的規範化表:

SELECT t.ticketid, u.userid, t.fullname, u.loginapi_userid, t.email, 
    tp.subject, tp.contents 
FROM swtickets t 
INNER JOIN swticketposts tp ON (t.ticketid = tp.ticketid) 
INNER JOIN swusers u ON (t.userid = u.userid) 
WHERE t.ticketid = 2458; 

然後查詢您的自定義字段,對結果集的多個行的結果:

SELECT cfv.customfieldid, cfv.fieldvalue 
FROM swcustomfieldvalues cfv 
WHERE cfv.typeid = 2458; 

你會得到多行結果集,每個自定義字段一行:

+---------------+--------------+ 
| customfieldid | fieldvalue | 
+---------------+--------------+ 
|    1 | 415-555-1234 | 
|    3 | Third office | 
|    5 | 123   | 
|    8 | Support  | 
|    9 | Engineering | 
+---------------+--------------+ 

然後您需要編寫應用程序以循環方式將結果集字段映射到應用程序對象字段的代碼。

以這種方式使用實體屬性值表在性能和代碼維護方面更具可擴展性。