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

MYSQL子查询行作为主查询中的列,mysql,sql,pivot,Mysql,Sql,Pivot,在我们的数据库中,我们有一个用户表和其他数据的键值表。我们一直在尝试提出一个将两者连接起来的查询,将k-v表中的键作为列标题,将值作为字段 到目前为止,我们唯一的解决方案是将每个用户的键值对作为一列进行分组,然后在查询输出缓慢且糟糕之后解析它们 以下是一般设置: User.db表: ------------------------------ | uid | firstname | lastname | ------------------------------ | 01 | john

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

到目前为止,我们唯一的解决方案是将每个用户的键值对作为一列进行分组,然后在查询输出缓慢且糟糕之后解析它们

以下是一般设置:

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   |
------------------------------------------------------

我希望有一个简单的方法来做到这一点,但一直未能找到任何东西。非常感谢所有帮助。

这将模拟数据透视表:

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:-)