1

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

到目前为止,我们唯一的解决方案是将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   |
------------------------------------------------------

我希望有一种简单的方法可以做到这一点,但一直找不到任何东西。所有帮助将不胜感激。

4

3 回答 3

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

但是如果你有未知的值,那么你可以使用准备好的语句来生成动态 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

两个版本都会产生相同的结果:

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

准备好的语句的好处是,如果您有更改的值,那么这将在运行时生成列列表。

于 2012-11-09T21:18:02.583 回答
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 来回答您的问题。

于 2012-11-09T20:11:19.747 回答
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
于 2012-11-09T20:14:14.527 回答