MYSQL子查询行作为主查询中的列

时间:2012-11-09 20:07:53

标签: mysql sql pivot

在我们的数据库中,我们有一个用户表和其他数据的键值表。我们一直试图提出一个将加入两者的查询,将k-v表中的键作为列标题,将值作为字段。

我们现在唯一的解决方案是将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 个答案:

答案 0 :(得分:4)

在其他数据库中,您可以使用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 :(得分:1)

这将模拟PIVOT表:

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回答您的问题。

答案 2 :(得分: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
相关问题