如何在不使用循环的情况下在SQL Server中更新两组不同标准之间的行

问题:如何在不使用循环的情况下在SQL Server中更新两组不同条件之间的行(SQL Server 2014)。换句话说,对于结果集中的每一行,如何更新第一次出现(具有一个标准)和第二次出现(具有不同的标准)之间的每一行。我认为部分问题是试图对查询中的每一行运行TOP N查询。

具体: 在下面的示例起始表中,如何在以下位置更新日期的后两列:

  1. 如果在空的类别行之前带有“ S”类别,则更新空的类别行和最后连续的“ M”类别行之间的行。类别可以包含“ S”,“ M”或空的任何顺序。

  2. 在空行之前设置“ S”行的StartDate = IDEndDate + 1天。

  3. 使用“ M”类别设置最后一行的EndDate = IDEndDate。

这里是SQLFiddle

注释:过去我是通过循环(抓取..)来完成此操作的,但是我试图通过一些查询来完成此操作,而不是像这样:

第1步:开始工作:选择所有有效的空行(范围开始)

步骤2:对于上面的每一行,选择相关的最后“ M”行(范围的结尾),然后运行查询以更新每个范围中的StartDate和EndDates。

Starting Table:
ID  IDStartDate IDEndDate   Category
------------------------------------
11  2017-01-01  2017-01-31  S
11  2017-02-02  2017-02-03  null
11  2017-02-03  2017-03-31  M
11  2017-04-01  2017-04-30  M
22  2017-05-01  2017-06-15  S
22  2017-06-16  2017-06-20  null
22  2017-06-21  2017-06-25  M
22  2017-06-26  2017-06-27  null
22  2017-06-28  2017-06-29  S
22  2017-06-30  2017-07-05  M
33  2017-06-30  2017-07-14  M
33  2017-07-15  2017-07-20  S
33  2017-07-21  2017-07-25  null
44  2018-06-30  2018-07-14  S
44  2018-07-15  2018-07-20  M
44  2018-07-21  2018-07-25  null


Desired Ending Table:
ID  IDStartDate IDEndDate  Category StartDate   EndDate 
----------------------------------------------------------
11  2017-01-01  2017-01-31 S        
11  2017-02-02  2017-02-03 null     2017-02-01  2017-04-30  
11  2017-02-03  2017-03-31 M        2017-02-01  2017-04-30
11  2017-04-01  2017-04-30 M        2017-02-01  2017-04-30
22  2017-05-01  2017-06-15 S        
22  2017-06-16  2017-06-20 null     2017-06-16  2017-06-25  
22  2017-06-21  2017-06-25 M        2017-06-16  2017-06-25
22  2017-06-26  2017-06-27 null
22  2017-06-28  2017-06-29 S
22  2017-06-30  2017-07-05 M
33  2017-06-30  2017-07-14 M
33  2017-07-15  2017-07-20 S
33  2017-07-21  2017-07-25 null
44  2018-06-30  2018-07-14 S
44  2018-07-15  2018-07-20 M
44  2018-07-21  2018-07-25 null

下面是一些SQL创建表并查看我已开始的查询结果。我尝试了CTE,交叉应用,外部应用,内部联接...没有运气。 非常感谢!

CREATE TABLE test (
    ID INT,IDStartDate date,IDEndDate date,Category VARCHAR (2),StartDate date,EndDate date
);
INSERT INTO test (ID,IDStartDate,IDEndDate,Category)
VALUES 
 (11,'2017-01-01','2017-01-31','S'),(11,'2017-02-02','2017-02-03',null),'2017-03-31','M'),'2017-04-01','2017-04-30',(22,'2017-05-01','2017-06-15','2017-06-16','2017-06-20','2017-06-21','2017-06-25','2017-06-26','2017-06-27','2017-06-28','2017-06-29','2017-06-30','2017-07-05',(33,'2017-07-14','2017-07-15','2017-07-20','2017-07-21','2017-07-25',(44,'2018-06-30','2018-07-14','2018-07-15','2018-07-20','2018-07-21','2018-07-25',null);


--**************************
--results: shows first rows of each range
--**************************
;with cte as
(
select *,ROW_NUMber() OVER(PARTITION BY ID ORDER BY ID,IDEndDate) AS RowNum,LAG(IDEndDate) OVER(PARTITION BY ID ORDER BY ID,IDEndDate) AS lastIDEndDate,LAG(Category) OVER(PARTITION BY ID ORDER BY ID,IDEndDate) AS lastCategory,LEAD(Category) OVER(PARTITION BY ID ORDER BY ID,IDEndDate) AS nextCategory
from test
)
select *  --select first row of each range to update
from cte
where Category is null and lastCategory = 'S' and nextCategory = 'M'


--*******************************
--6 of 8 "new" values are correct (missing NewEndDate for first range)
--*******************************
;with cte as
(
SELECT *,IDEndDate) AS nextCategory
FROM test
),cte2 as
(
select *        --find the first/start row of each range,LAG(RowNum) OVER(PARTITION BY ID ORDER BY ID,IDEndDate) AS lastRowNum,IIF(Category is null and lastCategory = 'S' and nextCategory = 'M',DateAdd(day,1,lastIDEndDate),null) as NewStartDate,RowNum,null) as NewStartRowNum
from cte
)
select t1.*,t3.*
from cte2 t1
outer apply
(       
  select top 1   --find the last/ending row of each range
   t2.lastIDEndDate as NewEndDate,t2.lastRowNum as NewEndRowNum
  from cte2 t2
  where t1.ID = t2.ID
  and t1.NewStartRowNum < t2.RowNum
  and t2.nextCategory <> 'M'  
  order by t2.ID,t2.RowNum
) t3
order by t1.ID,t1.RowNum
xiangan2010 回答:如何在不使用循环的情况下在SQL Server中更新两组不同标准之间的行

这是尝试解决此SQL难题的方法。

基本上,它是从CTE更新的。

首先,它计算累计和。创建某种排名。

然后仅对排名2和3进行计算。

;WITH CTE AS
(
    SELECT ID,IDStartDate,IDEndDate,Category,StartDate,EndDate,DATEADD(day,1,FIRST_VALUE(IDEndDate) OVER (PARTITION BY ID ORDER BY IDStartDate)) AS NewStartDate,FIRST_VALUE(IDEndDate) OVER (PARTITION BY ID ORDER BY IDStartDate DESC) AS NewEndDate
    FROM
    (
        SELECT ID,SUM(CASE WHEN Category = 'S' THEN 2 WHEN Category IS NULL THEN 1 END) OVER (PARTITION BY ID ORDER BY IDStartDate) AS cSum
        FROM test t
    ) q
    WHERE cSum IN (2,3)
)
UPDATE CTE
SET
    StartDate = NewStartDate,EndDate = NewEndDate
WHERE (Category IS NULL OR Category = 'M');

在妊娠here上进行的测试

,

我回答了我自己的问题。我有两个主要错误:

1)为使前N个查询正常工作,需要交叉应用(或外部应用)。 使用交叉应用,将对内部查询的每一行运行前N个查询。 使用内部联接(或左联接),将首先从内部查询返回所有行,并且前N个查询仅运行一次。

2)在“ [column] 'M'”上进行过滤使我感到困惑,因为它不排除NULL。我必须改用“ [[column] ='S'或[column]为空””

rextester中找到的最终SQL

下面的工作代码:

import DatePicker from "react-datepicker"
require('react-datepicker/dist/react-datepicker.css')
本文链接:https://www.f2er.com/3132306.html

大家都在问