问题描述
我有一个表格,其中包含按帐户划分的开始日期和结束日期的帐户所有权,但是,有些帐户存在重复,有些则具有与日期范围重叠的规则。我需要一个干净的结果集,显示帐户、所有者、开始日期和结束日期,没有重复或重叠。 源表如下所示:
账号 | 开始日期 | 结束日期 | 所有者 |
---|---|---|---|
1 | 3/1/2012 | 6/30/2012 | 约翰 |
1 | 3/1/2012 | 6/30/2012 | 约翰 |
1 | 5/31/2012 | 7/31/2015 | 约翰 |
2 | 5/1/2012 | 8/1/2012 | 账单 |
2 | 8/2/2012 | 10/31/2012 | 账单 |
2 | 12/1/2012 | 12/31/2012 | 乔 |
2 | 1/1/2013 | 12/31/2025 | 账单 |
我需要这样的结果
账号 | 开始日期 | 结束日期 | 所有者 |
---|---|---|---|
1 | 3/1/2012 | 7/31/2015 | 约翰 |
2 | 5/1/2012 | 10/31/2012 | 账单 |
2 | 12/1/2012 | 12/31/2012 | 乔 |
2 | 1/1/2013 | 12/31/2025 | 账单 |
非常感谢任何帮助。说到 sql,我是个新手。
Select distinct 删除了我的重复项,但我仍然得到多个重叠的日期范围。
我不知道我们使用的是什么版本的 sql server。它是一个名为 Sisense 的 BI 应用程序中的连接器,并没有真正说明。
这是我目前的选择语句:
select distinct
r.accountnumber,r.startdate,r.enddate,a.employeename Owner
from "dbo"."ruleset" r
left join "dbo"."rule" a on r.id = a.rulesetid
where
a.roleid = '1' and
r.isapproved = 'true'
解决方法
表结构有点有趣,虽然可能有更好的方法用更少的代码(即基于集合)来解决这个问题;这就是诀窍。这是我的解释和我的代码。
思考过程:我需要按照 AccountNumber 和 Owner 的顺序对行进行排序,并在其中任何一个发生变化时进行识别,因为这会标记一个新的“术语”;另外,我需要一种方法来标记每个“术语”的开头。前者我用了ROW_NUMBER
,后者我用了LAG
。这些记录以及 2 个新字段被插入到临时表中。
有了这 2 条信息,我就可以使用 WHILE
循环遍历行,跟踪当前行以及术语的最近开头。我用最新的结束日期更新每个学期的第一条记录(假设您没有较早的结束日期用于较晚的开始日期),一旦我们完成,我们只选择标记为新学期的记录,我们得到您要求的结果集。
文档链接。
RowNumber()
Lag
While
代码示例:
DECLARE @RowNumber INTEGER,@BeginTerm INTEGER,@EndDate DATE;
DROP TABLE IF EXISTS #OwnershipChange;
SELECT
r.accountNumber,r.startDate,r.endDate,a.employeename AS [owner],ROW_NUMBER()OVER(ORDER BY r.accountNumber,r.StartDate) RowNumber,0 AS Processed,CASE
WHEN a.employeename = LAG(a.employeename,1,NULL) OVER(ORDER BY r.accountNumber)
AND r.accountNumber = LAG(r.accountNumber,NULL)OVER(ORDER BY r.accountNumber)
THEN 0
ELSE 1
END AS NewOwnership
INTO #OwnershipChange
FROM dbo.ruleset r
LEFT OUTER JOIN dbo.rule a ON r.id = a.rulesetid
WHERE a.roleid = '1'
AND r.isapproved = 'true';
WHILE EXISTS (
SELECT 1/0
FROM #OwnershipChange
WHERE Processed = 0
)
BEGIN
SET @RowNumber = (
SELECT TOP 1 RowNumber
FROM #OwnershipChange
WHERE Processed = 0
ORDER BY RowNumber
);
SET @BeginTerm = (
SELECT
CASE
WHEN NewOwnership = 1 THEN @RowNumber
ELSE @BeginTerm
END
FROM #OwnershipChange
WHERE RowNumber = @RowNumber
);
SET @EndDate = (
SELECT endDate
FROM #OwnershipChange
WHERE RowNumber = @RowNumber
);
UPDATE #OwnershipChange
SET endDate = @EndDate
WHERE RowNumber = @BeginTerm;
UPDATE #OwnershipChange
SET Processed = 1
WHERE RowNumber = @RowNumber;
END;
SELECT
accountNumber,startDate,endDate,[owner]
FROM #OwnershipChange
WHERE NewOwnership = 1;