我们有一个表格,可以保存有关员工间隔的信息.我们称之为INTERVAL_TABLE.
我们在用户开始间隔和完成时保存.用户可以根据需要多次开始间隔,也可以按照自己的意愿完成多次.
这是一个简化的结构INTERVAL_TABLE:
INTERVAL_ID | USER_ID | INTERVAL_TYPE_ID | INTERVAL_TIMESTAMP | ENTRY_TYPE
Run Code Online (Sandbox Code Playgroud)
用户可以在表中包含以下条目:
现在,我们必须创建一个报告,该报告组合了该表的不同条目,这些条目引用相同的用户和间隔类型.我们应该能够识别具有开始和结束的间隔,并将这两个分组在一行中.假设上图中的数据,报告的输出应如下:
输出应按日期排序,如上图所示.
我不知道如何创建一个查询来做到这一点.
谢谢!
编辑 - 额外信息:
要找到任何INIT间隔的END间隔,我们应该根据该间隔的时间戳找到最接近的END间隔.这就是我们如何知道我们应该将ID 1与ID 2匹配而不是ID 3.
重要的是要注意,如果INIT间隔后跟另一个INIT间隔(基于时间戳),我们不应该继续为该INIT找到END.那是因为这是一个没有END的INIT.
LEAD使用和功能可以轻松有效地完成它LAG。至少它比表的自连接高效得多:O(n)vs O(n*n)。
首先使用LEAD和 以及LAG适当的为下一行和上一行添加列PARTITION BY。
然后构建两组对 - 第一个以 开头INIT_INTERVAL,第二个以 结尾END_INTERVAL。如果有一对同时具有 Init 和 End - 它将被包含两次,然后在 中被消除UNION。
示例数据(除了屏幕截图之外,您还应该将其包含在问题中)
CREATE TABLE INTERVAL_TABLE (
INTERVAL_ID int,
USER_ID int,
INTERVAL_TYPE_ID int,
INTERVAL_TIMESTAMP timestamp,
ENTRY_TYPE varchar(255));
INSERT INTO INTERVAL_TABLE (INTERVAL_ID, USER_ID, INTERVAL_TYPE_ID, INTERVAL_TIMESTAMP, ENTRY_TYPE) VALUES
(1, 1, 1, '2018-03-08 14:00:00', 'INIT_INTERVAL'),
(2, 1, 1, '2018-03-08 15:00:00', 'END_INTERVAL' ),
(3, 1, 1, '2018-03-08 15:30:00', 'END_INTERVAL' ),
(4, 1, 1, '2018-03-08 15:45:00', 'INIT_INTERVAL'),
(5, 1, 1, '2018-03-08 15:50:00', 'INIT_INTERVAL');
Run Code Online (Sandbox Code Playgroud)
询问
WITH
CTE
AS
(
SELECT
USER_ID
,INTERVAL_TYPE_ID
,ENTRY_TYPE AS Curr_Entry_Type
,INTERVAL_TIMESTAMP AS Curr_Interval_Timestamp
,INTERVAL_ID AS Curr_Interval_ID
,LAG(ENTRY_TYPE) OVER(PARTITION BY USER_ID, INTERVAL_TYPE_ID ORDER BY INTERVAL_TIMESTAMP) AS Prev_Entry_Type
,LAG(INTERVAL_TIMESTAMP) OVER(PARTITION BY USER_ID, INTERVAL_TYPE_ID ORDER BY INTERVAL_TIMESTAMP) AS Prev_Interval_Timestamp
,LAG(INTERVAL_ID) OVER(PARTITION BY USER_ID, INTERVAL_TYPE_ID ORDER BY INTERVAL_TIMESTAMP) AS Prev_Interval_ID
,LEAD(ENTRY_TYPE) OVER(PARTITION BY USER_ID, INTERVAL_TYPE_ID ORDER BY INTERVAL_TIMESTAMP) AS Next_Entry_Type
,LEAD(INTERVAL_TIMESTAMP) OVER(PARTITION BY USER_ID, INTERVAL_TYPE_ID ORDER BY INTERVAL_TIMESTAMP) AS Next_Interval_Timestamp
,LEAD(INTERVAL_ID) OVER(PARTITION BY USER_ID, INTERVAL_TYPE_ID ORDER BY INTERVAL_TIMESTAMP) AS Next_Interval_ID
FROM
INTERVAL_TABLE
)
,CTE_Result
AS
(
SELECT
USER_ID
,INTERVAL_TYPE_ID
,Curr_Entry_Type AS Entry_Type_Init
,Curr_Interval_Timestamp AS Interval_Timestamp_Init
,Curr_Interval_ID AS Interval_ID_Init
,Next_Entry_Type AS Entry_Type_End
,CASE WHEN Next_Entry_Type = 'END_INTERVAL' THEN Next_Interval_Timestamp END AS Interval_Timestamp_End
,CASE WHEN Next_Entry_Type = 'END_INTERVAL' THEN Next_Interval_ID END AS Interval_ID_End
FROM CTE
WHERE Curr_Entry_Type = 'INIT_INTERVAL'
UNION -- sic! not UNION ALL
SELECT
USER_ID
,INTERVAL_TYPE_ID
,Prev_Entry_Type AS Entry_Type_Init
,CASE WHEN Prev_Entry_Type = 'INIT_INTERVAL' THEN Prev_Interval_Timestamp END AS Interval_Timestamp_Init
,CASE WHEN Prev_Entry_Type = 'INIT_INTERVAL' THEN Prev_Interval_ID END AS Interval_ID_Init
,Curr_Entry_Type AS Entry_Type_End
,Curr_Interval_Timestamp AS Interval_Timestamp_End
,Curr_Interval_ID AS Interval_ID_End
FROM CTE
WHERE Curr_Entry_Type = 'END_INTERVAL'
)
SELECT
USER_ID
,INTERVAL_TYPE_ID
,Interval_Timestamp_Init
,Interval_Timestamp_End
,Interval_ID_Init
,Interval_ID_End
FROM CTE_Result
ORDER BY
USER_ID
,INTERVAL_TYPE_ID
,COALESCE(Interval_Timestamp_Init, Interval_Timestamp_End)
Run Code Online (Sandbox Code Playgroud)
| user_id | interval_type_id | interval_timestamp_init | interval_timestamp_end | interval_id_init | interval_id_end |
|---------|------------------|-------------------------|------------------------|------------------|-----------------|
| 1 | 1 | 2018-03-08T14:00:00Z | 2018-03-08T15:00:00Z | 1 | 2 |
| 1 | 1 | (null) | 2018-03-08T15:30:00Z | (null) | 3 |
| 1 | 1 | 2018-03-08T15:45:00Z | (null) | 4 | (null) |
| 1 | 1 | 2018-03-08T15:50:00Z | (null) | 5 | (null) |
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
546 次 |
| 最近记录: |