create table #customer (
id int not null primary key identity,
cust_no varchar(12),
meter_no varchar(10),
startdate smalldatetime,
enddate smalldatetime,
terminateDate smalldatetime,
oldid int null
)
insert into #customer values('AA111222','1111','2008-01-01', '2009-03-01','2008-04-15',null)
insert into #customer values('AA111222','1111','2008-01-01', '2009-05-01',null,null)
insert into #customer values('AA111222','1111','2008-03-01', '2008-12-01',null,null)
insert into #customer values('AA111222','1111','2009-05-01', '2009-07-01',null,null)
insert into #customer values('AA111222','1111','2009-08-01', '2009-11-01',null,null)
insert into #customer values('AA111222','1111','2010-01-01', '2010-04-01',null,null)
insert into #customer values('AA111222','1111','2010-07-01', '2011-07-01',null,null)
insert into #customer values('AA111222','1111','2011-03-01', '2011-07-01',null,null)
insert into #customer values('AA111222','1111','2011-07-01', '2012-07-01',null,null)
insert into #customer values('BB111222','1112','2011-03-01', '2011-07-01',null,null)
insert into #customer values('BB111222','1112','2011-07-01', '2012-07-01',null,null)
insert into #customer values('CC111222','1113','2011-09-01', '2012-07-01',null,null)
insert into #customer values('CC111222','1113','2011-03-01', '2011-07-01',null,null)
insert into #customer values('CC111222','1113','2011-07-01', '2012-07-01',null,null)
select * from #customer
场景:我们有超过10,000行。有些客户续费,其他则没有。我们想要构建层次结构
问题:根据oldID
和cust_no
共同提供标识特定客户的唯一组合这一事实,更新所有列的meter_no
列。
行1,2,3中需要的主要帮助都具有相同的cust_no, meter_no
和start_date
,这意味着它们属于同一个客户。由于startdate
是相同的,我们必须查看terminateDate
,如果两行具有相同的起始数据并且其中一行终止,则终止的行首先出现在层次结构中,另一行出现在后面
下面
oldid
应为1 oldid
应为2 oldid
应为null 我尝试了这个问题,这对我的旧问题Update oldID for the records recursively有效,但我被困在这里。在这个上花了不少时间。
Update #customer
SET oldid =
(Select TOP 1 c_old.id from #customer c_old
where c_old.startdate <= #customer.startdate
and c_old.cust_no = #customer.cust_no
and c_old.meter_no = #customer.meter_no
and c_old.id != #customer.id
and #customer.oldid is null
order by c_old.startdate desc,c_old.terminateDate desc
)
from #customer
我只是将数据转移到模型附近。
答案 0 :(得分:2)
以下是整个查询(包括上面的基本代码)。根据我与鳄鱼的聊天,结果完全符合要求。这个解决方案没有先前的递归,因为garreth指出它是不必要的。我确实在下面保留了递归解决方案,以防问题变得更复杂并且需要实际的递归。两种解决方案都应该有效,但
create table #customer (
id int not null primary key identity,
cust_no varchar(12),
meter_no varchar(10),
startdate smalldatetime,
enddate smalldatetime,
terminateDate smalldatetime,
oldid int null
)
insert into #customer values('AA111222','1111','2008-01-01', '2009-03-01','2008-04-15',null)
insert into #customer values('AA111222','1111','2008-01-01', '2009-05-01',null,null)
insert into #customer values('AA111222','1111','2008-03-01', '2008-12-01',null,null)
insert into #customer values('AA111222','1111','2009-05-01', '2009-07-01',null,null)
insert into #customer values('AA111222','1111','2009-08-01', '2009-11-01',null,null)
insert into #customer values('AA111222','1111','2010-01-01', '2010-04-01',null,null)
insert into #customer values('AA111222','1111','2010-07-01', '2011-07-01',null,null)
insert into #customer values('AA111222','1111','2011-03-01', '2011-07-01',null,null)
insert into #customer values('AA111222','1111','2011-07-01', '2012-07-01',null,null)
insert into #customer values('BB111222','1112','2011-03-01', '2011-07-01',null,null)
insert into #customer values('BB111222','1112','2011-07-01', '2012-07-01',null,null)
insert into #customer values('CC111222','1113','2011-09-01', '2012-07-01',null,null)
insert into #customer values('CC111222','1113','2011-03-01', '2011-07-01',null,null)
insert into #customer values('CC111222','1113','2011-07-01', '2012-07-01',null,null)
; WITH RankingCTE (id, cust_no, meter_no, startdate, enddate, terminatedate,
oldid, CustomerRank)
AS
(
SELECT *, ROW_NUMBER() OVER
(PARTITION BY cust_no, meter_no ORDER BY startdate, terminatedate)
AS CustomerRank
FROM #customer
)
UPDATE #customer
SET oldid = OrganizedCTE.OldID
FROM #customer
JOIN
( SELECT BaseCTE.ID, NextInRankCTE.ID AS OldID
FROM RankingCTE AS BaseCTE
LEFT JOIN RankingCTE AS NextInRankCTE
ON NextInRankCTE.Meter_No = BaseCTE.Meter_No
AND NextInRankCTE.Cust_No = BaseCTE.Cust_no
AND BaseCTE.CustomerRank = NextInRankCTE.CustomerRank + 1
) AS OrganizedCTE
ON OrganizedCTE.ID = #customer.ID
;
SELECT * FROM #customer
这是递归解决方案,还有完整的解决方案:
create table #customer (
id int not null primary key identity,
cust_no varchar(12),
meter_no varchar(10),
startdate smalldatetime,
enddate smalldatetime,
terminateDate smalldatetime,
oldid int null
)
insert into #customer values('AA111222','1111','2008-01-01', '2009-03-01','2008-04-15',null)
insert into #customer values('AA111222','1111','2008-01-01', '2009-05-01',null,null)
insert into #customer values('AA111222','1111','2008-03-01', '2008-12-01',null,null)
insert into #customer values('AA111222','1111','2009-05-01', '2009-07-01',null,null)
insert into #customer values('AA111222','1111','2009-08-01', '2009-11-01',null,null)
insert into #customer values('AA111222','1111','2010-01-01', '2010-04-01',null,null)
insert into #customer values('AA111222','1111','2010-07-01', '2011-07-01',null,null)
insert into #customer values('AA111222','1111','2011-03-01', '2011-07-01',null,null)
insert into #customer values('AA111222','1111','2011-07-01', '2012-07-01',null,null)
insert into #customer values('BB111222','1112','2011-03-01', '2011-07-01',null,null)
insert into #customer values('BB111222','1112','2011-07-01', '2012-07-01',null,null)
insert into #customer values('CC111222','1113','2011-09-01', '2012-07-01',null,null)
insert into #customer values('CC111222','1113','2011-03-01', '2011-07-01',null,null)
insert into #customer values('CC111222','1113','2011-07-01', '2012-07-01',null,null)
SELECT *, ROW_NUMBER() OVER
(PARTITION BY cust_no, meter_no ORDER BY startdate ASC, terminatedate ASC)
AS CustomerRank
INTO #RankingTable
FROM #customer
;WITH SortingCTE(id, cust_no, meter_no, startdate, enddate, terminatedate,
oldid, CustomerRank)
AS
(
-- Anchor member definition
SELECT id, cust_no, meter_no, startdate, enddate, terminatedate,
null as oldid, CustomerRank
FROM #RankingTable
WHERE CustomerRank = 1
UNION ALL
-- Recursive member definition
SELECT #RankingTable.id, #RankingTable.cust_no, #RankingTable.meter_no,
#RankingTable.startdate, #RankingTable.enddate,
#RankingTable.terminatedate, SortingCTE.id as oldid,
#RankingTable.CustomerRank
FROM #RankingTable
JOIN SortingCTE
ON SortingCTE.cust_no = #RankingTable.cust_no
AND SortingCTE.meter_no = #RankingTable.meter_no
AND SortingCTE.CustomerRank+1 = #RankingTable.CustomerRank
)
-- Statement that executes the CTE
UPDATE #customer
SET oldid = SortingCTE.oldid
FROM SortingCTE
JOIN #customer on #customer.id = SortingCTE.id
;
SELECT * FROM #customer
答案 1 :(得分:2)
我不认为递归是必要的,因为每个ID只回复到前一个记录,而不是最旧的ID。
;WITH CTE AS
( SELECT *, ROW_NUMBER() OVER(PARTITION BY Cust_no, Meter_No ORDER BY StartDate, TerminateDate) [RowNum]
FROM #Customer
)
UPDATE #Customer
SET OldID = cte.OldID
FROM #Customer c
INNER JOIN
( SELECT a.ID, b.ID [OldID]
FROM CTE a
LEFT JOIN CTE b
ON b.Meter_No = a.Meter_No
AND a.Cust_No = b.Cust_no
AND a.RowNum = b.RowNum + 1
) cte
ON cte.ID = c.ID
CTE并不是必需的,子查询同样可以正常工作,但是当我使用相同的子查询两次或更多时,我倾向于使用CTE。
答案 2 :(得分:2)
我认为@GarethD's solution可以像这样简化:
;
WITH CTE AS (
SELECT
*,
RowNum = ROW_NUMBER() OVER (
PARTITION BY Cust_no, Meter_No
ORDER BY StartDate, TerminateDate
)
FROM #Customer
)
UPDATE CTE
SET OldID = (
SELECT ID
FROM CTE a
WHERE CTE.Cust_no = a.Cust_no
AND CTE.Meter_no = a.Meter_no
AND CTE.RowNum = a.RowNum + 1
)