在我们的数据库中,我们有一个用户表和其他数据的键值表。我们一直试图提出一个将加入两者的查询,将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 |
------------------------------------------------------
我希望有一种直截了当的方法来做到这一点,但却找不到任何东西。非常感谢所有帮助。
答案 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;
但是如果您有未知值,那么您可以使用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;
两个版本都会产生相同的结果:
| 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