2013-07-10 53 views
1

我不確定這是否可行,並且描述確實很難。MySQL - 選擇內的子查詢

我想以這種方式返回SELECT查詢:

 
pID | Name | Email   | Dog Name | Fish Name 
------------------------------------------------------- 
44 | John | [email protected] | Scruffy | 
56 | Jane | [email protected] |   | Puffer 
72 | Joe | [email protected] | Sparky | Gill 

有3個表: tbl_option_fields tbl_person tbl_person_optionals

第一個表只定義無限的可選字段。下面是列:

 
optid | opttitle 
------------------ 
1  | Dog Name 
2  | Fish Name 
3  | Email 

第二個表只是,我保證數據的人:

 
pID | Name 
--------------- 
44 | John 
56 | Jane 
72 | Joe 

最後一個表讓我存儲的存在是有pID

 
ID | pID | optid | optval 
---------------------------------- 
1 | 44 | 1 | Scruffy 
2 | 56 | 2 | Puffer 
3 | 72 | 1 | Sparky 
4 | 72 | 2 | Gill 
5 | 72 | 3 | [email protected] 
6 | 56 | 3 | [email protected] 
7 | 44 | 3 | [email protected] 
任何可選數據

SELECT語句的結果需要在結果的標題中顯示opttitle。 我不擅長子查詢,這可能是一個愚蠢的。

這裏是我的嘗試:

SELECT p.*, opt.optval 
FROM `tbl_person` p 
LEFT OUTER JOIN `tbl_person_optionals` opt ON p.pID = opt.pID 
WHERE 1 

此查詢導致重複的結果,我相信我明白爲什麼。

 
pID | Name | optval    
----------------------------- 
44 | John | [email protected] 
44 | John | Scruffy 

56 | Jane | [email protected] 
56 | Jane | Puffer 

72 | Joe | [email protected] 
72 | Joe | Sparky 
72 | Joe | Gill 

希望我解釋說我想水平顯示可選字段,而不是行中的新記錄。 可以這樣做嗎?

+1

你在找什麼是一個數據透視查詢,但mysql不直接支持它們。有解決方法,但它們會導致醜陋的語法,並且當您在旋轉結果中添加/需要更多列時,它們不會自動放大。 –

+0

這可能是我需要聽到的。謝謝! – coffeemonitor

回答

0

你基本上想要的是一個數據透視表。這可以在MySQL中完成,如this article describes in full, glorious detail

然而,爲了archieve你將不得不在你的表tbl_option_fields添加SELECT - 運算符爲你擁有的每選擇要與當前的表設計的東西。只有少數幾個選項是可以管理的,但是您擁有的選項越多,您的聲明就會變得越混亂(並且最終執行速度會越慢)。

另一個缺點是每當有新選項出現時,您的陳述就必須進行調整。

基本上或者你必須忍受它或調整你的餐桌設計。可能還有更多的選擇,但我想可以歸結爲那兩個。

0

這裏有一個解決方案:

SELECT p.pID, p.Name, 
    MAX(IF(opt.optid=3, opt.optval, NULL)) AS `Email`, 
    MAX(IF(opt.optid=1, opt.optval, NULL)) AS `Dog Name`, 
    MAX(IF(opt.optid=2, opt.optval, NULL)) AS `Fish Name` 
FROM `tbl_person` p 
LEFT OUTER JOIN `tbl_person_optionals` opt ON p.pID = opt.pID 
GROUP BY p.pID; 

你必須知道所有的optid的和他們的標籤欄寫這個查詢之前。這對於MySQL來說是正確的,但支持本地PIVOT命令(例如Microsoft SQL Server)的RDBMS品牌也是如此。 SQL要求您在開始檢查數據之前定義查詢的列;該查詢不能「添加」更多的列,因爲它發現不同的數據值。

所以你應該查詢你的第一個表,它定義了可選字段,並使用結果動態地寫上面的SQL查詢。

另一種方法是按照您在示例中所示的方式逐行獲取可選字段,然後編寫應用程序代碼以獲取所有行並將其重新排列爲每人一行。

無論哪種方式:任何動態數據透視查詢都要求您在查詢之前或查詢之後編寫更多的應用程序代碼。

0

您可以通過加入表一起,並綜合這些結果做到這一點:

select po.pid, p.name, 
     MAX(case when o.optId = 'Email' then po.optval end) as Email, 
     MAX(case when o.optId = 'Dog Name' then po.optval end) as DogName, 
     MAX(case when o.optId = 'Fish Name' then po.optval end) as FishName 
from tbl_person_optionals po join 
    tbl_person p 
    on p.pId = p.pId join 
    tbl_optionfields o 
    on p.optid = o.optid 
group by po.pid, p.name; 

這是假設你知道你在列想要的東西。 Select語句只能返回一組固定的列,所以如果您想爲tbl_optionfields中的每個值返回一個單獨的列,則需要動態SQL(即使用prepare語句)。