【问题标题】:MySQL - Dynamic Pivot Table Grouping IssueMySQL - 动态数据透视表分组问题
【发布时间】:2016-07-06 07:43:05
【问题描述】:

我正在尝试使用 MySQL Prepared Statement 创建一个动态数据透视表,这是我从有关 MySQL 数据透视表的许多其他问题中汇总而成的。但我没有得到我期望的输出。

我的表格如下所示:

技能包含员工可以接受培训的所有“技能”

| id | skill   | expiry_date |
 ----+---------+-------------
| 1  | SkillA  | 2016-07-01  |
| 2  | SkillB  | 2016-06-01  |
| 3  | SkillC  | 2016-04-01  |

employee_skills 包含员工接受技能培训日期的日志

| id | employee_id | skill_id | date_trained |
 ----+-------------+----------+--------------
| 1  | 1000001     | 1        | 2016-05-01   |
| 2  | 1000002     | 1        | 2016-05-02   |
| 3  | 1000001     | 2        | 2016-05-03   |
| 4  | 1000002     | 3        | 2016-05-04   |

campaign_skills 包含已分配给“活动”的技能。

| id | campaign_id | skill_id |
 ----+-------------+----------
| 1  | 1001        | 1        |
| 2  | 1001        | 3        |
| 3  | 1002        | 2        |

我还有一个包含员工详细信息(first_namelast_name 等)的表格,其中 employee_id 作为主键。


期望的结果

这是我需要在视图中显示的内容:

| Employee    | SkillA     | SkillB      | SkillC      |
 -------------+------------+-------------+-------------
| Person One  | 2016-05-01 | 2016-05-03  | -           | 
| Person Two  | 2016-05-02 | -           | 2016-05-04  |

显示的日期应该是最近的employee_skills.date_trained

我还需要能够标记日期if ( employee_skills.date_trained < skills.expiry_date )。但我可以稍后再弄清楚。


我的查询

我编写了一个以campaign_id 作为参数的存储过程。我想我快到了,但我没有得到我期望的结果......

SET @sql = NULL;

SELECT 
    GROUP_CONCAT(DISTINCT
        CONCAT(
            'CASE WHEN skill = ''',
            s.skill,
            ''' THEN es.date_trained ELSE 0 END AS ',
            s.skill
        )
    ) INTO @sql
FROM  skills s
JOIN  campaign_skills cs ON cs.skill_id = s.id
WHERE cs.campaign_id = campaignID;

SET @sql = CONCAT('

    SELECT    CONCAT(e.first_name, " ", e.last_name) AS employee, ', @sql, ' 
    FROM      employees e
    LEFT JOIN employee_skills es ON es.employee_id = e.id
    LEFT JOIN campaign_skills cs ON cs.skill_id = es.skill_id
    LEFT JOIN skills s ON s.id = es.skill_id

    WHERE e.id IN (SELECT id FROM employees WHERE campaign_id = campaignID) 
        AND e.active = 1

    ORDER BY es.id DESC
    GROUP BY e.id, s.id

');

PREPARE statement FROM @sql;
EXECUTE statement;
DEALLOCATE PREPARE statement;

这将输出如下内容:

| employee   | SkillA     | SkillB     |
 ------------+------------+------------
| Person One | 2015-05-04 | -          |
| Person One | -          | 2016-05-01 |
| Person Two | -          | 2016-03-25 |
| Person Two | 2016-04-04 | -          |

即使我使用的是GROUP。我已经坚持了一段时间,所以也许有人可以告诉我我的错误?

SQL FIDDLE:http://sqlfiddle.com/#!9/7caa6c/1

【问题讨论】:

  • 在生成动态sql的时候尽量去掉JOIN campaign_skills cs ON cs.skill_id = s.id WHERE cs.campaign_id = campaignID
  • 如果我把这些线去掉,我仍然有同样的问题。唯一的区别是我获得了所有技能,而不是仅仅被campaign_id过滤。
  • sqlfiddle 我会试试的
  • @Drew 我添加了小提琴
  • 谢谢,等我喝完咖啡就去看看

标签: mysql sql stored-procedures group-by pivot-table


【解决方案1】:

以下 SQL 可以作为解决问题的起点:

SELECT
  es.employee_id,
  CONCAT(e.first_name, " ", e.last_name) AS employee,
  MAX(IF (es.skill_id = 1, es.date_trained, null)) AS '1',
  MAX(IF (es.skill_id = 2, es.date_trained, null)) AS '2',
  MAX(IF (es.skill_id = 3, es.date_trained, null)) AS '3'
FROM
  employee_skills es
  LEFT JOIN employees e ON es.employee_id = e.id
GROUP BY
  es.employee_id 

结果是这样的数据透视表:

| employee_id | employee   | 1          | 2          | 3          |
+-------------+------------+------------+------------+------------+
| 1001675     | Person Two | (null)     | 2016-07-02 | 2016-07-04 |
| 1006111     | Person One | 2016-07-01 | 2016-07-11 | (null)     |

如果 SQL 是动态创建的,则技能 ID 可以替换为技能名称。之后也可以替换 ID。

【讨论】:

  • 接受了这个作为答案 - 我所要做的就是在 CASE 语句周围添加 MAX()MAX(CASE WHEN ... END)。这意味着我只能按employee_id 分组并产生我想要的结果。
猜你喜欢
  • 1970-01-01
  • 2023-03-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-06-08
  • 2019-02-04
相关资源
最近更新 更多