简体   繁体   English

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

[英]MYSQL Subquery Rows as Columns in Main Query

In our database we have a user table, and key-value tables for other data.在我们的数据库中,我们有一个用户表和其他数据的键值表。 We have been trying to come up with a query that will join the two, taking the keys from the kv table as column headings, and the values as fields.我们一直在尝试提出一个将两者连接起来的查询,将 kv 表中的键作为列标题,将值作为字段。

Our only solution as of now is to GROUP_CONCAT the key-value pairs for each user as a column, and then parse them after the query has been output—slow and bad...目前我们唯一的解决方案是将每个用户的键值对GROUP_CONCAT作为一列,然后在查询输出后解析它们——缓慢而糟糕......

Here is the general setup:这是一般设置:

User.db Tables: 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 |
-----------------------------

The query result we'd like to get:我们想要得到的查询结果:

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

I'm hoping there's a straightforward way to do this, but haven't been able to find anything.我希望有一种直接的方法可以做到这一点,但一直找不到任何东西。 All help will be greatly appreciated.所有帮助将不胜感激。

In other database's you could use a PIVOT function but MySQL does not have that function so will have to replicate it using an aggregate function and a CASE statement.在其他数据库中,您可以使用PIVOT函数,但 MySQL 没有该函数,因此必须使用聚合函数和CASE语句复制它。 If you know all of the values, you can hard-code the values similar to this :如果您知道所有值,则可以对类似于以下内容的值进行硬编码:

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;

See SQL Fiddle with demo请参阅带有演示的 SQL Fiddle

But if you have unknown values, then you can use a prepared statement to generate dynamic SQL:但是如果你有未知的值,那么你可以使用准备好的语句来生成动态 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;

See SQL Fiddle with Demo参见SQL Fiddle with Demo

Both versions will generate the same result:两个版本都会产生相同的结果:

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

The benefit of the prepared statement is that if you have changing values, then this will generate the list of columns at run-time.准备好的语句的好处是,如果您有更改的值,那么这将在运行时生成列列表。

This would simulate a PIVOT table:这将模拟 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

There's also a solution with joins:还有一个带有连接的解决方案:

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'

Of course, you have to know in advance what the questions are.当然,你必须事先知道问题是什么。 If that's not the case, as far as I know, since MySql doesn't support PIVOT there's no way to answer your question using just standard SQL.如果情况并非如此,据我所知,由于 MySql 不支持 PIVOT,因此无法仅使用标准 SQL 来回答您的问题。

you can try something like that:你可以尝试这样的事情:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM