SQL - 如何进行转置操作?

32

我有一个类似下面表格的东西:

================================================
| Id | UserId | FieldName     | FieldValue     |
=====+========+===============+================|
| 1  | 100    | Username      | John Doe       |
|----+--------+---------------+----------------|
| 2  | 100    | Password      | pass123!       |
|----+--------+---------------+----------------|
| 3  | 102    | Username      | Jane           |
|----+--------+---------------+----------------|
| 4  | 102    | Password      | $ecret         |
|----+--------+---------------+----------------|
| 5  | 102    | Email Address | jane@email.com |
------------------------------------------------
我需要一个查询,能够给我一个类似这样的结果:
==================================================
| UserId | Username  | Password | Email Address  |
=========+===========+===========================|
| 100    | John Doe  | pass123! |                |
|--------+-----------+----------+----------------|
| 102    | Jane      | $ecret   | jane@email.com |
|--------+-----------+----------+----------------|
请注意,FieldName中的值不仅限于用户名、密码和电子邮件地址。它们可以是用户定义的任何内容。
有没有一种在SQL中实现这个的方法?

请参考 https://dev59.com/cHRB5IYBdhLWcg3wWGEH 查看类似问题。在应用程序中进行数据透视是否不可能,而保持查询简单?如果需要 N 个属性,则需要动态生成查询语句。 - Amitay Dobo
2个回答

56

MySQL不支持ANSI PIVOT/UNPIVOT语法,因此你需要使用以下方法:

  SELECT t.userid
         MAX(CASE WHEN t.fieldname = 'Username' THEN t.fieldvalue ELSE NULL END) AS Username,
         MAX(CASE WHEN t.fieldname = 'Password' THEN t.fieldvalue ELSE NULL END) AS Password,
         MAX(CASE WHEN t.fieldname = 'Email Address' THEN t.fieldvalue ELSE NULL END) AS Email
    FROM TABLE t
GROUP BY t.userid

正如您所看到的,CASE语句需要根据值进行定义。要使其具有动态性,您需要使用MySQL的准备语句(动态SQL)语法


@KLee - 所以他不需要按那些列进行分组 - dcp
6
由于case语句无法将查询结果展平,因此在不同的位置会出现null值。因此,您需要使用GROUP BY来展平查询 - MAX获取最高值,并且任何值都比NULL要高。 - OMG Ponies
2
+1. 棘手。希望我在MySQL方面足够娴熟,能够做出那样的事情。 - KLee1

1

你可以使用GROUP_CONCAT

(未经测试)

SELECT UserId, 
GROUP_CONCAT( if( fieldname = 'Username', fieldvalue, NULL ) ) AS 'Username', 
GROUP_CONCAT( if( fieldname = 'Password', fieldvalue, NULL ) ) AS 'Password', 
GROUP_CONCAT( if( fieldname = 'Email Address', fieldvalue, NULL ) ) AS 'Email Address', 
FROM table  
GROUP BY UserId

1
风险很大,因为如果ELSE部分没有返回NULL,GROUP_CONCAT将返回一个逗号分隔的列表。 - OMG Ponies

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接