将 2 行合并为 1 行

Posted

技术标签:

【中文标题】将 2 行合并为 1 行【英文标题】:merge 2 rows into 1 row 【发布时间】:2020-04-06 20:19:03 【问题描述】:

我想将每 2 行合并为一行

表:clock_activities

id      employee_id   activity     created_at
1       1             start_break  1:00
2       1             end_break    1:10
3       1             start_break  2:00
4       1             end_break    2:10
5       1             start_break  2:30
6       1             end_break    2:45        
7       1             start_break  3:10
8       1             end_break    3:20

我正在寻找的是这样的:

start    end       total
1:00     1:10      00:10
2:00     2:10      00:10
2:30     2:45      00:15
3:10     3:20      00:10

谁能指出我正确的方向?我在 *** 上找不到任何具有相同要求的内容。

【问题讨论】:

【参考方案1】:

使用自联接:

select c1.employee_id, 
  c1.created_at `start`, min(c2.created_at) `end`,
  time_format(timediff(
    min(c2.created_at),
    c1.created_at
  ), "%H:%i") total
from clock_activities c1 inner join clock_activities c2
on c1.employee_id = c2.employee_id
and c1.activity = 'start_break' and c2.activity = 'end_break'
and c1.created_at < c2.created_at
group by c1.employee_id, c1.created_at

请参阅demo。 结果:

| employee_id | start | end  | total |
| ----------- | ----- | ---- | ----- |
| 1           | 1:00  | 1:10 | 00:10 |
| 1           | 2:00  | 2:10 | 00:10 |
| 1           | 2:30  | 2:45 | 00:15 |
| 1           | 3:10  | 3:20 | 00:10 |

【讨论】:

【参考方案2】:

我会使用定义记录组的窗口总和来解决这个问题:每次看到'start_break',就会开始一个新组。然后你可以聚合:

select 
    employee_id,
    min(case when id = 'start_break' then created_at end) start_break,
    max(case when id = 'end_break' then created_at end) end_break,
    timestampdiff(
        minute, 
        max(case when id = 'end_break' then created_at end),
        min(case when id = 'start_break' then created_at end)
    ) total_minutes
from (
    select t.*, sum(activity = 'start_break') over(partition by employee_id order by id) grp
    from mytable t
)
group by employee_id, grp

【讨论】:

【参考方案3】:

对于每个开始,您都可以使用窗口函数获得下一个结束:

select employee_id, time, created_at as start_time, end_time,
       timestamp_diff(second, start_time, end_time)
from (select t.*,
             min(case when activity = 'end_break' then created_at end) over (partition by employee_id order by created_at desc) as end_time
      from t
     ) t
where activity = 'start_break';

【讨论】:

【参考方案4】:
    Select id,  min(activity='start_break')
      Over (partition by id<=id%2), 
     Min(activity='end_break')Over 
     (partition by id<=id%2),
     Min(Case when 
       activity='end_break' then 
      Date end) - Min(Case when 
       activity='start_break' then 
      Date end)Over (partition by 
       id<=id%2)
     From table

【讨论】:

以上是关于将 2 行合并为 1 行的主要内容,如果未能解决你的问题,请参考以下文章

Notepad++ 将 2 行合并为 1 行

使用 OpenOffice 将 3 行内容连接、合并或合并为 1 行

如何将多个行块合并为一个块?

将多个子行合并为一行MYSQL

使用 BusyBox 将 2 行合并为 key=value 字符串

SQL Server:将多行合并为 1 行