Как обновить последнюю запись с результатами второго lat [SQLServer] - PullRequest
10 голосов
/ 30 марта 2019

Я хочу обновить последнюю запись таблицы с результатом Pass / Fail из второй последней строки.И запрос не должен завершиться сбоем, если в таблице только одна строка.

Вот код, который у меня есть, но он обновляется только первыми записями, а не вторыми последними.спасибо за помощь

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 Server: 9.0.5057

Ответы [ 3 ]

5 голосов
/ 04 апреля 2019

Я не уверен, что следую. Даны такие данные:

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

Вы хотите обновить строку с TestergebnisID = 3 с помощью Pass и Fail из записи с TestergebnisID = 2 и все? Или запись 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
0 голосов
/ 02 апреля 2019

Если разделение недоступно, вы можете вставить последние две строки во временную таблицу. Таким образом, ваш максимум - это последний ряд, а ваш минимум - второй и последний ряд.

Это дает вам идентификатор для значения, которое вы хотите установить, и идентификатор строки, которую вы хотите обновить, вместе со значениями для использования.

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
0 голосов
/ 30 марта 2019

Если я правильно следил за вами, можно было бы упростить запрос с помощью обновляемого выражения общей таблицы, например:

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 использует оконные функции для:

  • ранжируйте каждую запись ROW_NUMBER() по убыванию TestergebnisID (используя ROW_NUMBER())
  • извлекает Pass и Fail предыдущей записи, TestergebnisID (с использованием LEAD())
  • операции выполняются в группах записей с одинаковым TestaufstellungID (вы можете просто удалить предложение WHERE в CTE, чтобы обработать все TestaufstellungID вместо одной из них)

Затем основной запрос просто выбирает наибольшую запись (rn = 1) и присваивает Pass и Fail из значений в предыдущей записи

...