2012-11-09 65 views
1

在我們的數據庫中,我們有一個用戶表和其他數據的鍵值表。我們一直試圖提出一個查詢來加入這兩個,將k-v表中的鍵作爲列標題,將值作爲字段。MYSQL子查詢行作爲主查詢中的列

我們作爲目前唯一的解決辦法是GROUP_CONCAT鍵 - 值對每個用戶爲一列,然後分析它們的查詢輸出緩慢和壞後...

這裏是一般設置:

的user.db表:

------------------------------ 
| uid | firstname | lastname | 
------------------------------ 
| 01 | john  | doe  | 
| 02 | jane  | doe  | 
------------------------------ 

----------------------------- 
| uid | question | answer | 
----------------------------- 
| 01 | question1 | answer1 | 
| 01 | question2 | answer2 | 
| 02 | question1 | answer3 | 
| 02 | question2 | answer4 | 
----------------------------- 

我們想查詢結果來獲得:

------------------------------------------------------ 
| uid | firstname | lastname | question1 | question2 | 
------------------------------------------------------ 
| 01 | john  | doe  | answer1 | answer2 | 
| 02 | jane  | doe  | answer3 | answer4 | 
------------------------------------------------------ 

我希望有一個簡單的方法來做到這一點,但一直沒能找到任何東西。所有的幫助將不勝感激。

回答

3

在其他數據庫的,你可以使用PIVOT功能,但MySQL不具有功能,因此將使用聚合功能和CASE語句來複制它。如果你知道所有的值,你可以硬編碼類似這樣的價值觀:

select u.uid, u.firstname, u.lastname, 
    max(case when question='question1' then answer else null end) as question1, 
    max(case when question='question2' then answer else null end) as question2 
from users u 
left join kv 
    on u.uid = kv.uid 
group by u.uid, u.firstname, u.lastname; 

SQL Fiddle with demo

但如果你有未知的值,那麼你可以使用一個prepared statement生成動態SQL:

SET @sql = NULL; 
SELECT 
    GROUP_CONCAT(DISTINCT 
    CONCAT(
     'max(case when question = ''', 
     question, 
     ''' then answer else NULL end) AS ', 
     question 
    ) 
) INTO @sql 
FROM kv; 

SET @sql = CONCAT('SELECT u.uid, u.firstname, u.lastname, ', @sql, ' 
        from users u 
        left join kv 
        on u.uid = kv.uid 
        group by u.uid, u.firstname, u.lastname'); 

PREPARE stmt FROM @sql; 
EXECUTE stmt; 
DEALLOCATE PREPARE stmt; 

SQL Fiddle with Demo

兩個版本都將產生相同的結果:

| UID | FIRSTNAME | LASTNAME | QUESTION1 | QUESTION2 | 
------------------------------------------------------ 
| 1 |  john |  doe | answer1 | answer2 | 
| 2 |  jane |  doe | answer3 | answer4 | 

準備語句的好處是,如果您有更改值,那麼這將在運行時生成列的列表。

1

這將模擬數據透視表:

Select 
    uid, 
    firstname, 
    lastname, 
    max(case when question = 'question1' then answer end) as question1, 
    max(case when question = 'question2' then answer end) as question2 
From 
    users inner join answers on users.uid = answers.uid 
Grop by uid, firstname, lastname 

還有一個解決方案與聯接:

Select uid, firstname, lastname, 
    answers_1.answer as question1, 
    answers_2.answer as question2 
From 
    users left join answers answers_1 
    on users.uid = answers_1.uid and answers_1.question = 'question1' 
    left join answers answers_2 
    on users.uid = answers_2.uid and answers_2.question = 'question2' 

當然,你必須提前知道什麼問題是。如果情況並非如此,據我所知,由於MySql不支持PIVOT,因此無法使用標準SQL來回答您的問題。

1

你可以嘗試這樣的事情:

select u.uid, u.firstname, u.lastname, 
    max(case when question="question1" then answer else null) as question1, 
    max(case when question="question2" then answer else null) as question2 
from user u join answers a on u.uid = a.uid 
group by u.uid, u.firstname, u.lastname 
+0

這些都很好,除非沒有單獨的查詢,我們不會知道任何「question1」,「question2」等標識符。有沒有什麼辦法可以將這個級別抽象出來? –

+0

你不可能真的有一個具有動態列數的查詢......所以你需要首先找到所有可能的問題,然後構建一個像上面那樣的查詢......或者去oracle :-) –