MYSQL子查询行作为主查询中的列
在我们的数据库中,我们有一个用户表和其他数据的键值表。我们一直在尝试提出一个将两者连接起来的查询,将k-v表中的键作为列标题,将值作为字段 到目前为止,我们唯一的解决方案是将每个用户的键值对作为一列进行分组,然后在查询输出缓慢且糟糕之后解析它们 以下是一般设置: User.db表:MYSQL子查询行作为主查询中的列,mysql,sql,pivot,Mysql,Sql,Pivot,在我们的数据库中,我们有一个用户表和其他数据的键值表。我们一直在尝试提出一个将两者连接起来的查询,将k-v表中的键作为列标题,将值作为字段 到目前为止,我们唯一的解决方案是将每个用户的键值对作为一列进行分组,然后在查询输出缓慢且糟糕之后解析它们 以下是一般设置: User.db表: ------------------------------ | uid | firstname | lastname | ------------------------------ | 01 | john
------------------------------
| 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 |
------------------------------------------------------
我希望有一个简单的方法来做到这一点,但一直未能找到任何东西。非常感谢所有帮助。这将模拟数据透视表:
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回答您的问题。这将模拟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回答您的问题。您可以尝试类似的方法:
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
您可以尝试类似的方法:
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
在其他数据库中,您可以使用
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:
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 |
prepared语句的好处是,如果您有更改的值,那么这将在运行时生成列列表。在其他数据库中,您可以使用
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:
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 |
准备好的语句的好处是,如果您有更改的值,那么这将在运行时生成列列表。这些都很好,只是如果没有单独的查询,我们将不知道“question1”、“question2”的任何标识符,等等。有没有办法把它抽象到一个层次上?你不可能真的有一个动态列数的查询。。。因此,您需要首先找到所有可能的问题,然后构造一个类似上面的查询。。。或者转到oracle:-)这些都很好,只是如果没有单独的查询,我们将不知道“question1”、“question2”等的任何标识符。有没有办法将其抽象到一个级别?您不能真正拥有一个具有动态列数的查询。。。因此,您需要首先找到所有可能的问题,然后构造一个类似上面的查询。。。或者转到oracle:-)