选择下一行,比较,设置以前的行

时间:2014-04-03 19:49:16

标签: sql sql-server sql-server-2008 conditional-statements

所以我在SQL-Server 2008中有一个名为Member_Phys_History的历史表

看起来像这样:

RecID, MemberID, Phys_ID, Phys_Start, Phys_End, Phys_Update

第一列是identityPhys_StartPhys_EndPhys_Update是日期。

我有另一张名为Member_Phys_Update

的表格
MemberID, Phys_ID, Phys_Start_Date

因此,每周大约一次,这个Update表会从客户端获得更新,其中Phys_ID发生变化,Phys_start会更晚......所以我将此信息添加到History表中,它看起来像这样:

1|ABC123|555|2014-01-01|NULL|NULL
2|ABC123|556|2014-04-01|NULL|NULL

以下是我需要做的事情:

我希望基本上将第一条记录Phys_End_Date设置为第二条记录Phys_Start_Date前一天。所以它看起来像这样:

1|ABC123|555|2014-01-01|2014-03-30|NULL
2|ABC123|556|2014-04-01|NULL|NULL

遗憾的是,我无法使用光标存储过程,我的DBA认为它效率低下。我想知道在几次查询中是否有任何办法可以做到这一点......

光标可能是理想的,但我可以使用FETCH NEXT或其他东西吗?

3 个答案:

答案 0 :(得分:4)

试试这个

Select A.*, B.Phys_End_Date
from table1 A
outer apply (select (min(Phys_Start_Date) - 1) Phys_End_Date from table1 x
             where x.Phys_Start_Date > A.Phys_Start_Date
             AND X.MemberID = A.MemberID) B

SQL DEMO

编辑(添加更新SQL)

update A
set A.Phys_End_Date = B.Phys_End_Date
from table1 A     
outer apply (select (min(Phys_Start_Date) - 1) Phys_End_Date from table1 x
             where x.Phys_Start_Date > A.Phys_Start_Date
             AND X.MemberID = A.MemberID) B

or

INSERT INTO table2 (memberid, phys_id,Phys_Start_Date,Phys_End_Date)
Select A.*, B.Phys_End_Date
from table1 A
outer apply (select (min(Phys_Start_Date) - 1) Phys_End_Date from table1 x
             where x.Phys_Start_Date > A.Phys_Start_Date
             AND X.MemberID = A.MemberID) B;

答案 1 :(得分:2)

作为替代方案,您可以使用Common Table表达式来完成它。

;WITH   base
          AS (
               SELECT *
                   ,ROW_NUMBER() OVER ( PARTITION BY MemberID ORDER BY Phys_Start ASC ) AS rn
                FROM Member_Phys_History 
             ),
        nextDate
          AS (
               SELECT *
                   ,ROW_NUMBER() OVER ( PARTITION BY MemberID ORDER BY Phys_Start ASC ) AS rn
                FROM Member_Phys_History 
             )
    SELECT b.RecID
           ,b.MemberID
           ,b.Phys_ID
           ,b.Phys_Start
           ,DATEADD(dd, -1, n.Phys_Start) AS Phy_End
           ,b.Phys_Update
        FROM base AS b
        LEFT OUTER JOIN nextDate AS n
            ON b.MemberID = n.MemberID
               AND b.rn = n.rn - 1;

将它变成UPDATE陈述

真的很容易
;WITH   base
          AS (
               SELECT *
                   ,ROW_NUMBER() OVER ( PARTITION BY MemberID ORDER BY Phys_Start ASC ) AS rn
                FROM Member_Phys_History 
             ),
        nextDate
          AS (
               SELECT *
                   ,ROW_NUMBER() OVER ( PARTITION BY MemberID ORDER BY Phys_Start ASC ) AS rn
                FROM Member_Phys_History 
             )
    UPDATE b
        SET b.Phys_End = DATEADD(dd, -1, n.Phys_Start)
        FROM base AS b
        LEFT OUTER JOIN nextDate AS n
            ON b.MemberID = n.MemberID
               AND b.rn = n.rn - 1;

答案 2 :(得分:0)

SQL小提琴 -

您不会在此处看到所有选择列。在您的SQL Server中运行它。 http://sqlfiddle.com/#!3/75dca/2

限制 - 仅当Phys_ID(您的表格)或代码(我的表格)是连续数字时,我的代码才有效。

自我加入的另一种方式 -

select *
from tblz as t1
inner join tblz as t2
on t1.id = t2.id
and (t1.code = t2.code - 1)

使用上述查询进行更新 -

update t1
set t1.EndDate = Dateadd(DAY, -1, t2.StartDate)
--select *
from tblz as t1
inner join tblz as t2
on t1.id = t2.id
and (t1.code = t2.code - 1)