如何用倒数第二个结果更新最后一条记录 [SQL Server]

How to update last record with second lat results [SQLServer]

我想用倒数第二行的 Pass/Fail 结果更新 table 的最后一个条目。如果 table.

中只有一行,查询就不会失败

这是我的代码,但它只更新第一个条目而不是倒数第二个条目。谢谢你的帮助

UPDATE DB.dbo.Testergebnisse 
SET 
    Pass = (
        SELECT TOP 1 Pass
        FROM DB.dbo.Testergebnisse
        WHERE 
            TestergebnisID != ( 
                SELECT MAX(TestergebnisID) FROM DB.dbo.Testergebnisse 
            )
            AND TestaufstellungID = 3166 
        ORDER BY TestergebnisID DESC
    ),
    Fail = (
        SELECT TOP 1 Fail
        FROM DB.dbo.Testergebnisse
        WHERE 
            TestergebnisID != ( 
                SELECT MAX(TestergebnisID)  FROM DB.dbo.Testergebnisse 
            ) 
            AND TestaufstellungID = 3166 
            ORDER BY TestergebnisID DESC
    )
WHERE 
    DB.dbo.Testergebnisse.TestergebnisID = ( 
        SELECT TOP 1 TestergebnisID 
        FROM DB.dbo.Testergebnisse 
        WHERE TestaufstellungID =  3166 
        ORDER BY TestergebnisID DESC
    )

SQL服务器版本:9.0.5057

如果我没听错,应该可以使用可更新的通用 Table 表达式来简化查询,例如:

WITH cte AS (
    SELECT 
        TestergebnisID, 
        TestaufstellungID,
        Pass, 
        Fail,
        ROW_NUMBER() OVER(PARTITION BY TestaufstellungID ORDER BY TestergebnisID DESC) rn,
        LEAD(Pass)    OVER(PARTITION BY TestaufstellungID ORDER BY TestergebnisID DESC) prev_pass,
        LEAD(Fail)    OVER(PARTITION BY TestaufstellungID ORDER BY TestergebnisID DESC) prev_fail
    FROM DB.dbo.Testergebnisse
    WHERE TestaufstellungID = 3166
)
UPDATE cte 
SET Pass = prev_pass, Fail = prev_fail 
WHERE rn = 1

CTE 使用 window 函数来:

  • 通过 TestergebnisID 降序排列每条记录 ROW_NUMBER()(使用 ROW_NUMBER()
  • 检索上一条记录的 PassFailTestergebnisID-wise(使用 LEAD()
  • 操作在具有相同 TestaufstellungID 的记录组内执行(您只需删除 CTE 中的 WHERE 子句即可处理所有 TestaufstellungID 而不是仅处理其中一个)

然后,主查询简单地选择最多记录的记录(rn = 1)并从上一条记录

中的值分配PassFail

如果分区不可用,您可以将最后两行插入临时 table。这样,您的最大值是最后一行,您的最小值是倒数第二行。

这会为您提供要设置的值的 ID 和要更新的行的 ID,以及要使用的值。

IF OBJECT_ID('tempdb..#Temp') IS NOT NULL
    DROP TABLE ##SourceValues
SELECT TOP 2 
TestergebnisID,Pass, Fail
INTO #Temp FROM Testergebnisse (NOLOCK)
WHERE TestaufstellungID = 3166
ORDER BY TestergebnisID DESC
DECLARE @LastId INT = (SELECT MAX(TestergebnisID) FROM #Temp)
DECLARE @SecondToLast INT = (SELECT MIN(TestergebnisID) FROM #Temp)
UPDATE DB.dbo.Testergebnisse SET Pass = (SELECT Pass FROM #Temp WHERE TestergebnisID = @SecondToLast) WHERE TestergebnisID = @LastID
UPDATE DB.dbo.Testergebnisse SET Fail = (SELECT Fail FROM #Temp WHERE TestergebnisID = @SecondToLast) WHERE TestergebnisID = @LastID

我不确定我是否在关注。给出这样的数据:

TestergebnisID TestaufstellungID Pass        Fail
-------------- ----------------- ----------- -----------
1              1                 10          12
2              1                 5           6
3              1                 3           4
4              2                 0           0

您想要使用 TestergebnisID = 2 的记录更新 TestergebnisID = 3 的行,仅此而已?或者记录 2 是否也应该使用记录 1 中的数据进行更新?

如果是前者,这应该可以解决问题:

;WITH rec AS
(
    SELECT this.TestaufstellungID 
         -- most recent for the given test run
         , MAX(this.TestergebnisID) AS LastTestergebnisID 
         -- find the previous 
         , PrevTestergebnisID =
           (SELECT MAX(prev.TestergebnisID) 
              FROM Testergebnisse prev 
             WHERE prev.TestaufstellungID = this.TestaufstellungID  
               AND prev.TestergebnisID < MAX(this.TestergebnisID )
           ) 
      FROM Testergebnisse this
     GROUP BY this.TestaufstellungID
)
UPDATE mostRecent
   SET Pass = prev.Pass
     , Fail = prev.Fail
  FROM Testergebnisse mostRecent
  JOIN rec
    ON rec.LastTestergebnisID = mostRecent.TestergebnisID 
  JOIN Testergebnisse prev
    ON prev.TestergebnisID = rec.PrevTestergebnisID 

给出:

TestergebnisID TestaufstellungID Pass        Fail
-------------- ----------------- ----------- -----------
1              1                 10          12
2              1                 5           6
3              1                 5           6       <-- 1 row affected
4              2                 0           0

如果您希望所有这些都使用其前身的值进行更新,则:

;WITH rec AS
(
    SELECT this.TestaufstellungID 
         -- most recent for the given test run
         , this.TestergebnisID
         -- find the previous 
         , PrevTestergebnisID =
           (SELECT MAX(prev.TestergebnisID) 
              FROM Testergebnisse prev 
             WHERE prev.TestaufstellungID = this.TestaufstellungID  
               AND prev.TestergebnisID < this.TestergebnisID
           ) 
      FROM Testergebnisse this
)
UPDATE mostRecent
   SET Pass = prev.Pass
     , Fail = prev.Fail
  FROM Testergebnisse mostRecent
  JOIN rec
    ON rec.TestergebnisID = mostRecent.TestergebnisID 
  JOIN Testergebnisse prev
    ON prev.TestergebnisID = rec.PrevTestergebnisID 

这将更新第 2 行(第 1 行)和第 3 行(第 2 行):

TestergebnisID TestaufstellungID Pass        Fail
-------------- ----------------- ----------- -----------
1              1                 10          12
2              1                 10          12       <--
3              1                 5           6        <--
4              2                 0           0