TSQL:在记录序列中查找记录组
TSQL: Find Groups of Records in a Sequence of Records
抱歉,如果您发现标题不正确,我真的不知道如何命名这个问题。这种 query/pattern.
可能有一个术语
我有一系列需要按日期排序的记录,这些记录有一个条件,我想 "group" 按 (SomeCondition) 以获得最早的开始日期和最晚的结束日期(取 NULL 的考虑在内),但我不确定如何完成查询(如果可能的话)。 table 中的原始记录看起来像;
-----------------------------------------------------------
| AbcID | XyzID | StartDate | EndDate | SomeCondition |
-----------------------------------------------------------
| 1 | 1 | 2018-01-01 | 2018-03-05 | 1 |
| 2 | 1 | 2018-04-20 | 2018-05-01 | 1 |
| 3 | 1 | 2018-05-02 | 2018-05-15 | 0 |
| 4 | 1 | 2018-06-01 | 2018-07-01 | 1 |
| 5 | 1 | 2018-08-01 | NULL | 1 |
| 6 | 2 | 2018-01-01 | 2018-06-30 | 1 |
| 7 | 2 | 2018-07-01 | 2018-08-31 | 0 |
-----------------------------------------------------------
我想要的结果是;
-----------------------------------
| XyzID | StartDate | EndDate |
-----------------------------------
| 1 | 2018-01-01 | 2018-05-01 |
| 1 | 2018-06-01 | NULL |
| 2 | 2018-01-01 | 2018-06-30 |
-----------------------------------
感谢任何 help/insight,即使是 "not possible"。
解决这个问题需要你一步一步来解决。以下是我用来执行此操作的步骤:
- 确定岛屿何时开始(当
SomeCondition
为false时)
- 通过对
IslandBegin
的数量求和,同时考虑 AbcID
order[=42] 中的记录,为每个岛屿(在每个 XyzID
内)创建一个 "ID" 数字=]
- 确定每个
XyzID
/IslandNumber
组合中的第一个和最后一个 AbcID
,其中 SomeCondition
为真
- 使用上一步作为指导,您应该为结果集中的每条记录获取
StartDate
/ EndDate
示例数据:
declare @sample_data table
(
AbcID int
, XyzID int
, StartDate date
, EndDate date
, SomeCondition bit
)
insert into @sample_data
values (1, 1, '2018-01-01', '2018-03-05', 1)
, (2, 1, '2018-04-20', '2018-05-01', 1)
, (3, 1, '2018-05-02', '2018-05-15', 0)
, (4, 1, '2018-06-01', '2018-07-01', 1)
, (5, 1, '2018-08-01', NULL, 1)
, (6, 2, '2018-01-01', '2018-06-30', 1)
, (7, 2, '2018-07-01', '2018-08-31', 0)
答案:
代码中的注释显示了 CTE 每个部分完成的步骤。
with island_bgn as
(
--Step 1
select d.AbcID
, d.XyzID
, d.StartDate
, d.EndDate
, d.SomeCondition
, case when d.SomeCondition = 0 then 1 else 0 end as IslandBegin
from @sample_data as d
)
, island_nbr as
(
--Step 2
select b.AbcID
, b.XyzID
, b.StartDate
, b.EndDate
, b.SomeCondition
, b.IslandBegin
, sum(b.IslandBegin) over (partition by b.XyzID order by b.AbcID asc) as IslandNumber
from island_bgn as b
)
, prelim as
(
--Step 3
select n.XyzID
, n.IslandNumber
, min(n.AbcID) as AbcIDMin
, max(n.AbcID) as AbcIDMax
from island_nbr as n
where 1=1
and n.SomeCondition = 1
group by n.XyzID
, n.IslandNumber
)
--Step 4
select p.XyzID
, a.StartDate
, b.EndDate
from prelim as p
inner join @sample_data as a on p.AbcIDMin = a.AbcID
inner join @sample_data as b on p.AbcIDMax = b.AbcID
order by p.XyzID
, a.StartDate
, b.EndDate
结果:
+-------+------------+------------+
| XyzID | StartDate | EndDate |
+-------+------------+------------+
| 1 | 2018-01-01 | 2018-05-01 |
+-------+------------+------------+
| 1 | 2018-06-01 | NULL |
+-------+------------+------------+
| 2 | 2018-01-01 | 2018-06-30 |
+-------+------------+------------+
抱歉,如果您发现标题不正确,我真的不知道如何命名这个问题。这种 query/pattern.
可能有一个术语我有一系列需要按日期排序的记录,这些记录有一个条件,我想 "group" 按 (SomeCondition) 以获得最早的开始日期和最晚的结束日期(取 NULL 的考虑在内),但我不确定如何完成查询(如果可能的话)。 table 中的原始记录看起来像;
-----------------------------------------------------------
| AbcID | XyzID | StartDate | EndDate | SomeCondition |
-----------------------------------------------------------
| 1 | 1 | 2018-01-01 | 2018-03-05 | 1 |
| 2 | 1 | 2018-04-20 | 2018-05-01 | 1 |
| 3 | 1 | 2018-05-02 | 2018-05-15 | 0 |
| 4 | 1 | 2018-06-01 | 2018-07-01 | 1 |
| 5 | 1 | 2018-08-01 | NULL | 1 |
| 6 | 2 | 2018-01-01 | 2018-06-30 | 1 |
| 7 | 2 | 2018-07-01 | 2018-08-31 | 0 |
-----------------------------------------------------------
我想要的结果是;
-----------------------------------
| XyzID | StartDate | EndDate |
-----------------------------------
| 1 | 2018-01-01 | 2018-05-01 |
| 1 | 2018-06-01 | NULL |
| 2 | 2018-01-01 | 2018-06-30 |
-----------------------------------
感谢任何 help/insight,即使是 "not possible"。
解决这个问题需要你一步一步来解决。以下是我用来执行此操作的步骤:
- 确定岛屿何时开始(当
SomeCondition
为false时) - 通过对
IslandBegin
的数量求和,同时考虑AbcID
order[=42] 中的记录,为每个岛屿(在每个XyzID
内)创建一个 "ID" 数字=] - 确定每个
XyzID
/IslandNumber
组合中的第一个和最后一个AbcID
,其中SomeCondition
为真 - 使用上一步作为指导,您应该为结果集中的每条记录获取
StartDate
/EndDate
示例数据:
declare @sample_data table
(
AbcID int
, XyzID int
, StartDate date
, EndDate date
, SomeCondition bit
)
insert into @sample_data
values (1, 1, '2018-01-01', '2018-03-05', 1)
, (2, 1, '2018-04-20', '2018-05-01', 1)
, (3, 1, '2018-05-02', '2018-05-15', 0)
, (4, 1, '2018-06-01', '2018-07-01', 1)
, (5, 1, '2018-08-01', NULL, 1)
, (6, 2, '2018-01-01', '2018-06-30', 1)
, (7, 2, '2018-07-01', '2018-08-31', 0)
答案:
代码中的注释显示了 CTE 每个部分完成的步骤。
with island_bgn as
(
--Step 1
select d.AbcID
, d.XyzID
, d.StartDate
, d.EndDate
, d.SomeCondition
, case when d.SomeCondition = 0 then 1 else 0 end as IslandBegin
from @sample_data as d
)
, island_nbr as
(
--Step 2
select b.AbcID
, b.XyzID
, b.StartDate
, b.EndDate
, b.SomeCondition
, b.IslandBegin
, sum(b.IslandBegin) over (partition by b.XyzID order by b.AbcID asc) as IslandNumber
from island_bgn as b
)
, prelim as
(
--Step 3
select n.XyzID
, n.IslandNumber
, min(n.AbcID) as AbcIDMin
, max(n.AbcID) as AbcIDMax
from island_nbr as n
where 1=1
and n.SomeCondition = 1
group by n.XyzID
, n.IslandNumber
)
--Step 4
select p.XyzID
, a.StartDate
, b.EndDate
from prelim as p
inner join @sample_data as a on p.AbcIDMin = a.AbcID
inner join @sample_data as b on p.AbcIDMax = b.AbcID
order by p.XyzID
, a.StartDate
, b.EndDate
结果:
+-------+------------+------------+
| XyzID | StartDate | EndDate |
+-------+------------+------------+
| 1 | 2018-01-01 | 2018-05-01 |
+-------+------------+------------+
| 1 | 2018-06-01 | NULL |
+-------+------------+------------+
| 2 | 2018-01-01 | 2018-06-30 |
+-------+------------+------------+