Обновить идентификатор рекурсивно - PullRequest
0 голосов
/ 28 февраля 2012
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

Сценарий: У нас более 10000 строк.Некоторые клиенты обновляются, другие нет.Мы хотим построить иерархию

Проблема: Обновите столбец oldID всех столбцов, основываясь на том факте, что cust_no и meter_no вместе дают уникальную комбинацию, которая идентифицирует конкретного клиента.

Основная помощь - это потребности в строках 1,2,3, которые имеют одинаковые cust_no, meter_no и start_date, что означает, что они принадлежат одному и тому же клиенту.Поскольку startdate одинаков, мы должны взглянуть на terminateDate, если две строки имеют одинаковые начальные данные и одна из них завершена, завершенная строка идет первой в иерархии, а другая - позже.

Здесь

  • строка # 3 oldid должна быть 1
  • строка # 1 oldid должна быть 2
  • строка # 2 oldid должнабыть нулевым
  • Остальное в значительной степени в хронологическом порядке.

Я пытался выполнить этот запрос, который сработал для моего старого вопроса Рекурсивно обновить oldID для записей , но я застрял здесь.Потратьте немало времени на это.

 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

Я просто воспроизвел данные, близкие к модели.

Ответы [ 3 ]

2 голосов
/ 28 февраля 2012

Я не думаю, что рекурсия необходима, поскольку каждый идентификатор возвращается только к предыдущей записи, а не к самому старому идентификатору.

;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 голосов
/ 29 февраля 2012

Я думаю, @ решение GarethD можно упростить так:

;
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
)
2 голосов
/ 28 февраля 2012

Ниже приведен весь запрос (включая базовый код сверху). В моем чате с крокодилом результаты совпадают именно так, как запрошено. Это решение не имеет предшествующей рекурсии, поскольку Гаррет указал, что оно не является необходимым. Я оставил рекурсивное решение ниже на случай, если проблема станет более сложной и потребует рекурсии. Оба решения должны работать, хотя

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
...