sql 根据当前行的值对前几行求和

sql sum previous rows based on value of current row

我有以下 table

CREATE TABLE #tbl (
    RoomTypeId INT NOT NULL,
    DayNo TINYINT NOT NULL,
    RoomNo TINYINT NOT NULL,
    IsDormitory BIT,
    AdultsNo TINYINT NOT NULL,
    Tmp TINYINT)
insert into #tbl (RoomTypeId, DayNo, RoomNo, IsDormitory, AdultsNo, Tmp) values(2486, 98, 1, 1, 1, 0)
insert into #tbl (RoomTypeId, DayNo, RoomNo, IsDormitory, AdultsNo, Tmp) values(2486, 99, 1, 1, 1, 0)
insert into #tbl (RoomTypeId, DayNo, RoomNo, IsDormitory, AdultsNo, Tmp) values(2486, 98, 2, 1, 2, 0)
insert into #tbl (RoomTypeId, DayNo, RoomNo, IsDormitory, AdultsNo, Tmp) values(2486, 99, 2, 1, 2, 0)
insert into #tbl (RoomTypeId, DayNo, RoomNo, IsDormitory, AdultsNo, Tmp) values(2487, 98, 1, 0, 2, 0)
insert into #tbl (RoomTypeId, DayNo, RoomNo, IsDormitory, AdultsNo, Tmp) values(2487, 99, 1, 0, 2, 0)

仅对于 IsDormitory = 1 的那些行,我想使用如下值更新字段 Tmp:对于具有特定 RoomNo 的每个房间,Tmp 列 = RoomNo <= 当前所有房间的所有 AdultsNo 的总和房间号

示例:

结果将是:

RoomTypeId  DayNo RoomNo  IsDormitory  AdultsNo Tmp
2486        98    1       1            1        1
2486        99    1       1            1        1
2486        98    2       1            2        3
2486        99    2       1            2        3 
2487        98    1       0            2        0
2487        99    1       0            2        0

以下无效:

update #tmp2 set TmpAdults = Adults from #tmp2 t inner join 
(select RoomTypeId, DayNo, sum(AdultsNo) as Adults from #tmp2 x where      x.RoomNo  < t.RoomNo) s on t.RoomTypeId = s.RoomTypeId and t.DayNo = s.DayNo

;with CTE as
(
select RoomTypeId, DayNo, sum(AdultsNo) as Adults from #tmp2 group by RoomTypeId, DayNo
)
update #tmp2 set TmpAdults = c.Adults from #tmp2 t
inner join CTE c on t.RoomTypeId = c.RoomTypeId and t.DayNo = c.DayNo

我正在使用 Microsoft SQL Server 2014。

我不知道如何使用 CTE,但根据我的阅读,这应该是答案。 谢谢。

更新:

我添加了 2 行:

insert into #tbl (RoomTypeId, DayNo, RoomNo, IsDormitory, AdultsNo, Tmp) values(2486, 98, 3, 1, 1, 0)
insert into #tbl (RoomTypeId, DayNo, RoomNo, IsDormitory, AdultsNo, Tmp) values(2486, 99, 3, 1, 1, 0)

但不幸的是答案并不如我所料。我希望 RoomNo = 3 Tmp = 1+2+1=4,而不是我得到 2

RoomTypeId  DayNo RoomNo  IsDormitory  AdultsNo Tmp
2486        98    3       1            1        4
2486        99    3       1            1        4 

您可以使用 CTE 来更新:

;WITH ToUpdate AS (
   SELECT t1.AdultsNo + COALESCE(t3.AdultsNo,0) AS AdultsNo,
          Tmp
   FROM #tbl AS t1
   OUTER APPLY (
      SELECT DISTINCT AdultsNo
      FROM #tbl AS t2
      WHERE t2.RoomNo < t1.RoomNo) AS t3
   WHERE IsDormitory = 1
)
UPDATE ToUpdate
SET Tmp = AdultsNo

CTE 使用 OUTER APPLY 操作来获取先前记录(如果有)的 AdultsNo 值。

此 CTE 应该会为您提供结果,然后它很简单 JOIN 并执行更新。

不过你对多个临时表的使用让我担心...

;WITH MyCTE AS
(
    SELECT
        RoomTypeID,
        DayNo,
        RoomNo,
        IsDormitory,
        AdultsNo,
        SUM(CASE WHEN IsDormitory = 1 THEN AdultsNo ELSE 0 END) OVER (PARTITION BY RoomTypeID, DayNo ORDER BY RoomNo ROWS UNBOUNDED PRECEDING) AS Tmp
    FROM
        #tbl
)
SELECT *
FROM MyCTE
update #tbl
set Tmp = (
    select sum(t2.AdultNo) from #tbl t2
    where t2.RoomTypeID = #tbl.RoomTypeID and t2.DayNo = #tbl.DayNo
        and t2.RoomNo <= #tbl.RoomNo
)
where IsDormitory = 1

我相信 MySQL 在更新的子查询中引用相同的 table 有问题,但我很确定 SQL 服务器对此没有问题。您可以使用别名在内部查询中进行关联,但这确实不标准 SQL。请注意,内部查询不限于宿舍房间,因为从问题中不清楚这就是您所需要的。