Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/jpa/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 递归更新id_Sql_Sql Server 2005_Join - Fatal编程技术网

Sql 递归更新id

Sql 递归更新id,sql,sql-server-2005,join,Sql,Sql Server 2005,Join,场景:我们有超过10000行。一些客户续订,另一些则不续订。我们想要建立层次结构 问题:根据cust_no和meter_no共同提供识别特定客户的唯一组合这一事实,更新所有列的oldID列 主要帮助是第1、2、3行中的“需要”,它们都有相同的客户号、仪表号和开始日期,这意味着它们属于同一客户。因为startdate是相同的,所以我们必须查看terminateDate,如果两行具有相同的开始数据,并且其中一行被终止,那么终止的行在层次结构中位于第一位,而另一行位于第二位 这里 第3行oldid应为

场景:我们有超过10000行。一些客户续订,另一些则不续订。我们想要建立层次结构

问题:根据cust_no和meter_no共同提供识别特定客户的唯一组合这一事实,更新所有列的oldID列

主要帮助是第1、2、3行中的“需要”,它们都有相同的客户号、仪表号和开始日期,这意味着它们属于同一客户。因为startdate是相同的,所以我们必须查看terminateDate,如果两行具有相同的开始数据,并且其中一行被终止,那么终止的行在层次结构中位于第一位,而另一行位于第二位

这里

第3行oldid应为1 第1行oldid应为2 第2行oldid应为空 其余的基本上是按时间顺序排列的。 我尝试了这个问题,这个问题对我的老问题有效,但我被困在这里了。在这件事上花了不少时间

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

我只是在模型附近复制了数据。

下面是整个查询,包括上面的基本代码。根据我与鳄鱼的聊天,结果完全符合要求。正如garreth指出的那样,这个解决方案没有前面的递归,它是不必要的。我确实保留了下面的递归解决方案,以防问题变得更复杂,需要实际的递归。不过,这两种解决方案都应该有效

 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
这是递归解决方案,完整解决方案也是:

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

我不认为递归是必要的,因为每个ID只恢复到前一个记录,而不是最旧的ID

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
CTE并不是真正必要的,子查询也同样有效,但当我使用同一子查询两次或更多次时,我倾向于使用CTE。

我认为可以这样简化:

;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

我以前做过,但运气不好:我唯一好奇的是,为什么第2行的id为空,不是3吗?第2行是最古老的记录基记录,所以它应该有空的oldid。实际上,我一开始并没有考虑这个问题。前9行是相同的,那么它们是什么ID呢?如果您可以填写整个示例集所需的id,这可能会很有用?只是为了澄清你的规则?好吧,我认为你发布的数据是错误的,首先?第三行有一个不同的开始日期,但您的解释好像它是相同的开始日期?不过,我还是不太确定基于您的示例,您的逻辑是如何工作的?我不明白你为什么说订单是什么?您能否在发布数据时再次检查数据,然后告诉我们示例数据在转换后的样子?这将有助于更容易地理解您的逻辑规则。最好使用更快、更清晰的查询。对所有记录执行Mine需要4分钟以上的时间。第1-3行的开始日期不同。第1行和第2行的开始日期为01-01-08,而第3行的开始日期为03-01-08???,所以enddate在这里不起作用?也许最好不要在示例中使用它。是的,enddate不起作用,但可能可以在某些容量中使用。因为记录9、11和12是每个客户的最新记录,因此它们不能是旧ID,因为我理解这个问题。你很可能是对的,我仍然不了解这些要求。你是对的。在这种情况下不需要递归。我想我简化了,然后我自己检查了一下,结果与@JustinPihony发布的答案相同,这些评论让我相信这不是OP想要的,所以我所做的只是简化了一个错误的答案,这对任何人都没有多大帮助……事实上,我不确定是什么问题,因为我和鳄鱼聊天,我的结果完全符合他想要的。我会好奇地想知道这个问题这是我的第一个想法,然后当我测试时,我得到了意想不到的结果,我刚刚在家里再次尝试,得到了我预期的结果。。。奇怪,我之前一定写错了。我同意这是简化的,而且更有效。它也符合SQL标准,并且使用SQL server的更新。。。从…起加入anomoly。@GarethD解决方案效果非常好。但我有一个问题,如果没有提供终止日期,那么它会选择错误的旧ID。有一种方法可以使用ISNULL并使所有带有null的记录显示在顶部而不是底部,因为在我的例子中它们是活动记录。现在调查一下。今天我考虑了另一个逻辑,要创建一个临时表,首先对数据进行排序,然后使用allready排序表中的数据更新oldid字段
;
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
)