2017-02-05 6 views
0

У меня есть некоторые данные, которые выглядят так: http://sqlfiddle.com/#!6/21a06/1Обновление некоторых столбцов одной строки из другой таблицы же

id step valA valB valC 
------------------------------ 
100 1  NULL 2  3 
101 2  4  5  6 
102 3  7  NULL 9 
103 3  10  11  12 
104 4  13  14  15 
105 4  NULL 14  15 
106 5  NULL 18  19 
107 5  20  18  19 

идентификатор является уникальным полем. Я пытаюсь найти запрос, который будет обновлять значения в данной строке из определенных столбцов (в этом примере valA и valB) следующей строки. Только там, где «шаг» обеих строк соответствует (никогда не ожидается, что будет соответствовать более чем двум строкам), если значение столбца valA или valB равно NULL в первой строке (с более низким значением listid), значение того же столбец из следующей строки копируется в первую строку.

Так, в приведенном выше примере таблицы строка для id = 102 должна иметь значение valB, обновленное до 11 (для соответствия valB следующей строки с id = 103). Кроме того, строка для id = 106 должна иметь значение valA до 20 (для соответствия valA следующей строки с id = 107). Любая заданная пара строк может одновременно выполнять условия как для valA, так и для valB (оба значения NULL). id = 100 строка не изменяется, потому что нет другой строки с шагом = 1, а строка id = 105 также не затрагивается, потому что NULL находится во второй строке пары «шаг».

Результат будет выглядеть следующим образом:

id step valA valB valC 
------------------------------ 
100 1  NULL 2  3 
101 2  4  5  6 
102 3  7  11  9 
103 3  10  11  12 
104 4  13  14  15 
105 4  NULL 14  15 
106 5  20  18  19 
107 5  20  18  19 

Если это делает его легче, то NULL на ид = 105 строке также может быть обновлен до значения от ид = 104 ряда (13), но это не так необходимо.

Я нашел несколько вопросов, которые были связаны друг с другом, и я пробовал разные вещи с помощью внутренних соединений и т. Д., Но не смог придумать что-нибудь, что сработало. Это выходит за рамки моего базового опыта SQL. Любая помощь приветствуется.

ответ

0

Вы можете использовать ROW_NUMBER, чтобы получить первую строку соответствующей пары. Затем используйте APPLY, чтобы получить второе значение из второй пары.

WITH CTE AS(
    SELECT *, 
     Rn = ROW_NUMBER() OVER(PARTITION BY step ORDER BY id) 
    FROM TestTable 
) 
SELECT 
    c.id, 
    c.step, 
    valA = ISNULL(c.valA, x.valA), 
    valB = ISNULL(c.valB, x.valB), 
    c.valC 
FROM CTE c 
OUTER APPLY(
    SELECT TOP(1) * 
    FROM TestTable t 
    WHERE 
     t.id > c.id 
     AND t.step = c.step 
    ORDER BY t.id 
) x 
WHERE 
    Rn = 1 
    OR (c.valA IS NULL OR c.valB IS NULL) 

UNION ALL 

SELECT 
    id, step, valA, valB, valC 
FROM CTE 
WHERE 
    Rn = 2 
    AND valA IS NOT NULL 
    AND valB IS NOT NULL 
ORDER BY Id; 

ONLINE DEMO

+0

Спасибо! Я переживаю это, чтобы понять, как он работает лучше, но похоже, что он будет делать то, что мне нужно. Кажется, что изменения сделаны в c, а не в исходной таблице. Например. если я следую с помощью select * из TestTable, я получаю исходные данные. Возможно ли это сделать так, чтобы исходные строки таблицы были изменены? – AngeloQ