MySQL 将行旋转到动态列
MySQL Pivoting Rows to Dynamic Columns
我们有一个 table,其中包括如下 entrance/exit 人的记录:
Person
Day
Time
1
02/21/2021
08:10
2
02/21/2021
08:11
1
02/21/2021
08:45
1
02/21/2021
09:18
1
02/21/2021
10:45
7
02/21/2021
10:53
2
02/21/2021
17:06
1
02/21/2021
17:23
7
02/21/2021
17:31
1
02/22/2021
08:13
5
02/22/2021
08:19
2
02/22/2021
08:20
2
02/22/2021
08:23
5
02/22/2021
09:47
5
02/22/2021
11:03
5
02/22/2021
18:06
5
02/22/2021
19:08
2
02/22/2021
19:01
5
02/22/2021
22:37
5
02/23/2021
08:15
1
02/23/2021
08:15
1
02/23/2021
14:30
5
02/23/2021
17:05
有了这些数据,我们想 select 它们如下:
Person
Day
Time1
Time2
Time3
Time4
Time5
Time6
1
02/21/2021
08:10
08:45
09:18
10:45
17:23
2
02/21/2021
08:11
17:06
7
02/21/2021
10:53
17:31
1
02/22/2021
08:13
2
02/22/2021
08:20
08:23
19:01
5
02/22/2021
08:19
09:47
11:03
18:06
19:08
22:37
1
02/23/2021
08:15
14:30
5
02/23/2021
08:15
17:05
最简单的解决方案不是在 SQL 中执行此操作,而是通过简单查询获取所有数据:
SELECT person, day, time FROM WeHaveATable ORDER BY day, person, time;
然后编写应用程序代码以根据需要在网格中显示它。
这在 SQL 中很棘手的原因是 SQL 要求您在准备查询之前拼出 select 列表中的所有列。那是在它有机会读取数据以了解次数最多的人会有多少列之前。
SQL 无法通过读取数据并根据读取数据时发现的内容将更多列附加到 select 列表来生成“动态列”。
所以在SQL中做一个枢轴的方法是你首先必须知道有多少列。
SELECT MAX(c) FROM (SELECT COUNT(*) FROM WeHaveATable GROUP BY person) AS t;
然后使用 window 函数形成一个查询,对每个 person/day 的行进行编号,并在 pivot-table 查询中使用它,每次一列,向上到您在上一个查询中获得的最大次数。
WITH cte AS (
SELECT person, day, time, ROW_NUMBER() OVER (PARTITION BY day, person ORDER BY time) AS colno
FROM WeHaveATable;
)
SELECT day, person,
MAX(CASE colno WHEN 1 THEN time END) AS Time1,
MAX(CASE colno WHEN 2 THEN time END) AS Time2,
MAX(CASE colno WHEN 3 THEN time END) AS Time3,
MAX(CASE colno WHEN 4 THEN time END) AS Time4,
MAX(CASE colno WHEN 5 THEN time END) AS Time5,
MAX(CASE colno WHEN 6 THEN time END) AS Time6
FROM cte
GROUP BY day, person;
如果这看起来像是很多令人费解的细致工作,那么您是对的。这就是为什么建议在 SQL 中跳过解决这个问题的原因。执行我在顶部显示的简单查询,然后编写应用程序代码以按照需要将结果处理到网格中。
有关列需求的数据驱动列表,请参阅http://mysql.rjweb.org/doc.php/pivot
它构建 SELECT
并可选择运行它。
我们有一个 table,其中包括如下 entrance/exit 人的记录:
Person | Day | Time |
---|---|---|
1 | 02/21/2021 | 08:10 |
2 | 02/21/2021 | 08:11 |
1 | 02/21/2021 | 08:45 |
1 | 02/21/2021 | 09:18 |
1 | 02/21/2021 | 10:45 |
7 | 02/21/2021 | 10:53 |
2 | 02/21/2021 | 17:06 |
1 | 02/21/2021 | 17:23 |
7 | 02/21/2021 | 17:31 |
1 | 02/22/2021 | 08:13 |
5 | 02/22/2021 | 08:19 |
2 | 02/22/2021 | 08:20 |
2 | 02/22/2021 | 08:23 |
5 | 02/22/2021 | 09:47 |
5 | 02/22/2021 | 11:03 |
5 | 02/22/2021 | 18:06 |
5 | 02/22/2021 | 19:08 |
2 | 02/22/2021 | 19:01 |
5 | 02/22/2021 | 22:37 |
5 | 02/23/2021 | 08:15 |
1 | 02/23/2021 | 08:15 |
1 | 02/23/2021 | 14:30 |
5 | 02/23/2021 | 17:05 |
有了这些数据,我们想 select 它们如下:
Person | Day | Time1 | Time2 | Time3 | Time4 | Time5 | Time6 |
---|---|---|---|---|---|---|---|
1 | 02/21/2021 | 08:10 | 08:45 | 09:18 | 10:45 | 17:23 | |
2 | 02/21/2021 | 08:11 | 17:06 | ||||
7 | 02/21/2021 | 10:53 | 17:31 | ||||
1 | 02/22/2021 | 08:13 | |||||
2 | 02/22/2021 | 08:20 | 08:23 | 19:01 | |||
5 | 02/22/2021 | 08:19 | 09:47 | 11:03 | 18:06 | 19:08 | 22:37 |
1 | 02/23/2021 | 08:15 | 14:30 | ||||
5 | 02/23/2021 | 08:15 | 17:05 |
最简单的解决方案不是在 SQL 中执行此操作,而是通过简单查询获取所有数据:
SELECT person, day, time FROM WeHaveATable ORDER BY day, person, time;
然后编写应用程序代码以根据需要在网格中显示它。
这在 SQL 中很棘手的原因是 SQL 要求您在准备查询之前拼出 select 列表中的所有列。那是在它有机会读取数据以了解次数最多的人会有多少列之前。
SQL 无法通过读取数据并根据读取数据时发现的内容将更多列附加到 select 列表来生成“动态列”。
所以在SQL中做一个枢轴的方法是你首先必须知道有多少列。
SELECT MAX(c) FROM (SELECT COUNT(*) FROM WeHaveATable GROUP BY person) AS t;
然后使用 window 函数形成一个查询,对每个 person/day 的行进行编号,并在 pivot-table 查询中使用它,每次一列,向上到您在上一个查询中获得的最大次数。
WITH cte AS (
SELECT person, day, time, ROW_NUMBER() OVER (PARTITION BY day, person ORDER BY time) AS colno
FROM WeHaveATable;
)
SELECT day, person,
MAX(CASE colno WHEN 1 THEN time END) AS Time1,
MAX(CASE colno WHEN 2 THEN time END) AS Time2,
MAX(CASE colno WHEN 3 THEN time END) AS Time3,
MAX(CASE colno WHEN 4 THEN time END) AS Time4,
MAX(CASE colno WHEN 5 THEN time END) AS Time5,
MAX(CASE colno WHEN 6 THEN time END) AS Time6
FROM cte
GROUP BY day, person;
如果这看起来像是很多令人费解的细致工作,那么您是对的。这就是为什么建议在 SQL 中跳过解决这个问题的原因。执行我在顶部显示的简单查询,然后编写应用程序代码以按照需要将结果处理到网格中。
有关列需求的数据驱动列表,请参阅http://mysql.rjweb.org/doc.php/pivot
它构建 SELECT
并可选择运行它。