【问题标题】:MySQL - Pivot row values into column groups based on value of another columnMySQL - 根据另一列的值将行值透视到列组中
【发布时间】:2021-07-29 21:40:08
【问题描述】:

我正在尝试构建产品比较页面。我有以下 MySQL 表。将 item_id 列视为 product_id

+---------+------------------+-------------------------+
| item_id | field_name       | field_value             |
+---------+------------------+-------------------------+
|       1 | Operating System | Windows 7               |
|       1 | Processor        | Core i3                 |
|       1 | Brand            | HP                      |
|       2 | Operating System | Windows 10              |
|       2 | Processor        | Core i7                 |
|       2 | Brand            | Dell                    |
+---------+------------------+-------------------------+

我试图获得一个结果,我可以将 item1 (item_id=1) 和 item2 (item_id=2) 的品牌、操作系统和处理器的值作为单行并排比较。要比较的产品数量(即:- 列)最少两个,最多四个。

我已经看到在这里找到的答案 -> MySQL pivot row into dynamic number of columns 但不同之处在于我的动态列基于 item_id 的值,而 field_name 值将用于一列。 field_value 的值将根据 item_id 添加到动态列中。根据答案,我尝试了以下基于案例的语句,但它创建了一些不必要的空值

SELECT 
    field_name,
    CASE
        WHEN price_fid = 1 THEN field_value
    END AS item1,
    CASE
        WHEN price_fid = 2 THEN field_value
    END AS item2
FROM
    custom_fields;

结果:

+------------------+-----------+-------------------------+
| field_name       | item1     | item2                   |
+------------------+-----------+-------------------------+
| Operating System | Windows 7 | NULL                    |
| Processor        | Core i3   | NULL                    |
| Brand            | HP        | NULL                    |
| Operating System | NULL      | Windows 10              |
| Processor        | NULL      | Core i7                 |
| Brand            | NULL      | Dell                    |
+------------------+-----------+-------------------------+

如您所见,品牌、操作系统和处理器在 field_name 列中出现两次,并且 item1 和 item2 都有空值。 我还查看了以下答案 -> Pivot values on column based on grouped columns in SQL 但仍然存在空值或重复字段名称的问题。

我想要获得的是单行上两个项目(产品)的值。这是我正在寻找的结果。

+------------------+-----------+------------+
| field_name       | item1     | item2      |
+------------------+-----------+------------+
| Brand            | HP        | Dell       |
| Operating System | Windows 7 | Windows 10 |
| Processor        | Core i3   | Core i7    |
+------------------+-----------+------------+

是否可以运行 MySQL 查询来获得上述输出?如果是这样,有没有办法轻松添加第三个和第四个 item_id (即:- 列)。 我正在寻找一个基于案例或其他类型的查询,我可以轻松地从 PHP 调用。如果不能通过标准的 mysql 查询,我仍然不介意 t-sql 语句或过程。 谢谢

【问题讨论】:

  • 为什么不处理应用程序代码中的表示问题?

标签: mysql


【解决方案1】:

一种更加动态的方法是。

你可以在第一条sql语句中加一个WHERE item_id IN (1,2,3,4),然后选择你想看的item_ids

CREATE TABLE custom_fields (
  `item_id` INTEGER,
  `field_name` VARCHAR(16),
  `field_value` VARCHAR(10)
);

INSERT INTO custom_fields
  (`item_id`, `field_name`, `field_value`)
VALUES
  ('1', 'Operating System', 'Windows 7'),
  ('1', 'Processor', 'Core i3'),
  ('1', 'Brand', 'HP'),
  ('2', 'Operating System', 'Windows 10'),
  ('2', 'Processor', 'Core i7'),
  ('2', 'Brand', 'Dell');
SET @sql = NULL;
SELECT
  GROUP_CONCAT(DISTINCT
    CONCAT(
      'MAX(case when item_id = ''',
      item_id,
      ''' then field_value ELSE NULL END) AS item',
      item_id
    )
  ) INTO @sql
from custom_fields;

SET @sql = CONCAT('SELECT field_name, ', @sql, ' FROM custom_fields
group by field_name');

PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
字段名 |项目1 |项目2 :--------------- | :-------- | :--------- 操作系统 |视窗 7 |视窗 10 处理器 |酷睿 i3 |酷睿 i7 品牌 |惠普 |戴尔

db小提琴here

【讨论】:

  • 我注意到的一件事是,如果您有一个新行,其中 item_id = 3、field_name = 'Display' 和 field_value='6.5 inch',在使用建议的查询时,您仍然会得到一个row where field_name = Display 并且动态列值等于 null。我在最后一个 sql 语句中添加了 where item_id in (1, 2) 。有没有办法避免那些 item_id 不等于 1 或 2 的行。
  • 对我来说它看起来很完美dbfiddle.uk/… 因为 otem1 和 2 没有任何显示,它不能在表格中具有值,这就是表格的工作方式,所以告诉我什么让你期待,我会看到,但我认为你应该让它做应用,但如果你看到像戴尔这样的网站并且他们比较 Displays .with Mouse,他们有相似的输出,但他们也有一个订单行,他们设置一个 orer的显示事物。但在现实中,您总是会将 aples 与 apples 进行比较,因此基本类别应该与低空值相等
【解决方案2】:

您可以group by field_name 并使用条件聚合:

SELECT field_name,
       MAX(CASE WHEN item_id = 1 THEN field_value END) item1,
       MAX(CASE WHEN item_id = 2 THEN field_value END) item2,
       MAX(CASE WHEN item_id = 3 THEN field_value END) item3 -- for a 3d column
       .....................................................
FROM custom_fields
GROUP BY field_name

请参阅demo

【讨论】:

  • 完全按照我的意愿工作。我其实很喜欢你的回答,因为它更短,可以很容易地从 php 中实现。
  • 我注意到的一件事是,如果您有一个新行,其中 item_id = 3、field_name = 'Display' 和 field_value='6.5 inch',在使用查询时,您仍然会得到一行其中 field_name = 显示且动态列值等于 null。有没有办法避免那些 item_id 不等于 1 或 2 的结果中的行。
  • @user3659497 您发布的示例数据的模式意味着如果您有 field_name = 'Display' 它将在所有 item_ids 中,就像在所有 item_ids 中存在的 Brand 一样,在这种情况下代码有效很好:dbfiddle.uk/…
猜你喜欢
  • 2018-03-15
  • 2020-01-11
  • 2016-01-23
  • 1970-01-01
  • 2022-01-23
  • 2020-10-10
  • 1970-01-01
  • 1970-01-01
  • 2023-03-17
相关资源
最近更新 更多