使用另一个表中的行值将它们选择为列并建立它们之间的关系(数据透视表)

问题描述 投票:0回答:1

有一个下表,名为

fields

还有一个专门的表来存储其值,称为

values

我想运行查询以产生以下输出:

Finished | Faculity  | Characteristic | Photo
---------------------------------------------
   1     |    Math   |        Good    |     
   0     |  Biology  |     Not Good   |          

我想构建一个输出上述结果的查询。但这并不像看起来那么容易。从这个类似的问题,我尝试运行以下查询:

SELECT flds.id,
  (case when flds.name = 'Finished' THEN vals.value END) AS Finished,
  (case when flds.name = 'Faculty' THEN vals.value END) AS Faculty,
  (case when flds.name = 'Characteristic' THEN vals.value END) AS Characteristic,
  (case when flds.name = 'Photo' THEN vals.value END) AS Photo
  
FROM `values` vals

LEFT JOIN `fields` flds
  ON vals.field_id = flds.id
  
GROUP BY
    flds.id,
    vals.value;

这给了我意想不到的结果:

有什么办法可以解决吗?

sql mysql pivot-table
1个回答
0
投票

假设对于

field_values
中的每个 id,
fields
中的行数相等。也就是说这个查询返回一个
1
:

SELECT CASE 
        WHEN EXISTS(
                SELECT 1
                FROM(
                    SELECT COUNT(*) AS cnt
                    FROM field_values
                    GROUP BY field_id
                    ) subq
                HAVING MAX(subq.cnt) <> MIN(subq.cnt)
                )
            THEN 0
            ELSE 1
        END AS test;

否则,解决方案将需要一堆 FULL JOINS 并且会变得混乱。特别是由于 MySQL 没有 FULL JOIN,因此您必须将所有 LEFT/RIGHT ANTI JOIN 与 RIGHT/LEFT JOIN(分别)联合起来。

创建表格并填充示例数据

-- Create your tables
DROP TABLE IF EXISTS fields;
CREATE TABLE fields (id BIGINT NOT NULL
                    , name VARCHAR(100) NOT NULL
                    );

INSERT INTO fields(id
                , name
                )
VALUES(19, 'Finished')
    , (20, 'Faculty')
    , (21, 'Characteristic')
    , (27, 'Photo');
    
DROP TABLE IF EXISTS field_values;
CREATE TABLE field_values(id BIGINT NOT NULL
                        , field_id BIGINT NOT NULL
                        , `value` VARCHAR(100)
                        );

INSERT INTO field_values(id
                , field_id
                , `value` 
                )
VALUES(1, 20, 'Math')
    , (2, 21, 'Good')
    , (3, 19, '1')
    , (4, 27, NULL)
    , (5, 20, 'Biology')
    , (6, 21, 'Not good')
    , (7, 19, '0')
    , (8, 27, NULL);

将字段与 field_values 连接,跟踪 field_values 中 id 的顺序。因为我还假设您想使用该值来确定最终的显示顺序。

将此结果与自身连接,以获得最终结果中所需数量的列,并匹配适当的序数位置。

WITH base
AS
(
    SELECT fv.id
        , fv.`value`
        , f.name
        , ROW_NUMBER() OVER(PARTITION BY f.id ORDER BY fv.id ASC) AS rn
    FROM fields f
    INNER JOIN field_values fv
        ON f.id = fv.field_id
)

SELECT col1.`value` AS Finished
    , col2.`value` AS Faculty
    , col3.`value` AS Characteristic
    , col4.`value` AS Photo
FROM(
    SELECT `value`
        , rn
    FROM base
    WHERE name = 'Finished'
    ) col1
INNER JOIN (
    SELECT `value`
        , rn
    FROM base
    WHERE name = 'Faculty'
    ) col2
    ON col1.rn = col2.rn
INNER JOIN (
    SELECT `value`
        , rn
    FROM base
    WHERE name = 'Characteristic'
    ) col3
    ON col2.rn = col3.rn
INNER JOIN (
    SELECT `value`
        , rn
    FROM base
    WHERE name = 'Photo'
    ) col4
    ON col3.rn = col4.rn;

自己尝试一下:db<>fiddle

© www.soinside.com 2019 - 2024. All rights reserved.