【问题标题】:Converting vertical Table to Horizontal table将垂直表转换为水平表
【发布时间】:2018-12-31 14:00:51
【问题描述】:

我正在为这个操作寻找一个干净、快速和好的解决方案。 首先我有一个看起来像这样的表

field_id   -    item_id   -   value
   1        -     781  -       name1
   2        -     781   -      lastname1
   3        -     781   -      phone1
   1        -     782   -      name2
   2        -     782   -      lastname2
   3        -     782   -      phone2
   1        -     783   -      name3
   2        -     783   -      lastname3
   3        -     783   -      phone3

我想这样显示这个表格:

item_id    -    name   -   lastname   -   phone
781     -        name1    -  lastname1   -   phone1
782     -        name2    -  lastname2   -   phone2   
783     -        name3    -  lastname3   -   phone3

我试过了

SELECT field_id, item_id,
(CASE WHEN field_id = 1 THEN value END) AS name,
(CASE WHEN field_id = 2 THEN value END) AS lastname,
(CASE WHEN field_id = 3 THEN value END) AS phone
FROM cq6xb_fields_values
GROUP BY item_id;

但我得到了这个奇怪的结果

item_id    -    name   -   lastname   -   null 
781     -        null -  lastname1   -   null 
782     -        null -  lastname2   -   null 
783     -        null -  lastname3   -   null 

【问题讨论】:

  • 是的,这很有意义。您正在尝试分组而不是同时在一个查询中分组,您不能同时拥有它。如果字段不在 GROUP BY 中,则只能在 SELECT 中使用 MIN()、MAX()、SUM() 等聚合函数。因此,您不能使用 field_id,因为您会得到随机结果。它不知道应该从三个记录中的哪一个中选择field_id。
  • 无论如何,它会在每个 CASE 语句中为 field_id 使用相同的值,并且您需要三个不同的值。我的朋友,选择中的一列不能有多个值。因此,在您的情况下,MySQL 会为每个 item_id 随机选择值 2,也可能是 1 或 3,而不是其他列将是 NULL。
  • 顺便说一下,表结构很糟糕。但这可能不是你的错,我意识到这一点。但是,如果可以的话,只需制作一个包含字段 item_id、姓名、姓氏和电话的表格,然后将其扔掉。更精彩的一点是:请参阅我的答案。
  • 或见 P. Salmon's
  • 谢谢,我搜索了很多不同的方法,但没有一个像 P.Salmo 的那样效果很好。我害怕提出一个菜鸟问题,但你们太棒了,这是我第一次在这里提出问题,我真的很高兴我做到了。

标签: mysql group-by case


【解决方案1】:

你不远了,只要加上max,你就可以删除字段id,因为你不使用它。

SELECT item_id,
max(CASE WHEN field_id = 1 THEN value END) AS name,
max(CASE WHEN field_id = 2 THEN value END) AS lastname,
max(CASE WHEN field_id = 3 THEN value END) AS phone
FROM cq6xb_fields_values
GROUP BY item_id;

+---------+-------+-----------+--------+
| item_id | name  | lastname  | phone  |
+---------+-------+-----------+--------+
|     781 | name1 | lastname1 | phone1 |
|     782 | name2 | lastname2 | phone2 |
|     783 | name3 | lastname3 | phone3 |
+---------+-------+-----------+--------+
3 rows in set (0.00 sec)

【讨论】:

  • 简单又好用!比我的简单。不过,我希望 OP 明白为什么这行得通,而他却没有。而且我仍然认为他应该尽可能地改变他的表结构。
  • @roemer 这被称为条件聚合,SO中有很多例子。
  • 我还没有在 SO 上发现它,但我自己过去也使用过类似的构造,但出于其他原因。感谢您回复并为我命名,现在这会更好地记住。
  • 谢谢,它工作得很好,我是 MySQL 新手,我想要实现的是将一些 joomla 自定义字段合并到一个更友好/可读的界面中。这个解决方案的执行速度也非常快,不像我尝试过的一些 Join 需要很长时间。
  • 连接可能会显示,因为连接字段没有被索引,所以你知道。
【解决方案2】:

注意:在您的问题下查看我的 cmets,表结构本质上是不好的,这就是为什么它变得如此复杂。

如果您真的想要这种方式,您需要加入限制为所属 field_id 值的表,或者使用子查询。

所以这可以工作:

SELECT main.item_id, names.value AS name, lastnames.value AS lastname, phones.value AS phone
FROM cq6xb_fields_values AS main
    LEFT JOIN cq6xb_fields_values AS names ON names.item_id = main.item_id AND names.field_id=1
    LEFT JOIN cq6xb_fields_values AS lastnames ON lastnames.item_id = main.item_id AND lastnames.field_id=2
    LEFT JOIN cq6xb_fields_values AS phones ON phones.item_id = main.item_id AND phones.field_id=3
GROUP BY main.item_id

【讨论】:

  • 谢谢,我之前尝试过类似的方法,但是由于字段数量更多,所以速度很慢,结构是 joomla 使用的本机自定义字段,所以我无法更改。
猜你喜欢
  • 2011-02-08
  • 1970-01-01
  • 2017-08-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多