Найти последнюю запись в цепочке из одной таблицы (SQL Server)

Получил эту таблицу в SQL Server 2005, которая используется для ведения истории операций слияния:

  • Столбец FROM_ID (целое число)
  • Столбец TO_ID (целое число)

Теперь мне нужен запрос, который принимает исходный FROM_ID в качестве входных данных и возвращает последний доступный TO_ID.

Так, например:

  • ID 1 объединяется с ID 2
  • Позже идентификатор 2 объединяется с идентификатором 3.
  • Позже снова ID 3 объединяется с ID 4.

Таким образом, запрос, который я пытаюсь составить, примет в качестве входных данных (в предложении WHERE, как я полагаю) ID 1 и в результате должен дать мне последний доступный TO_ID, в данном случае 4.

Я полагаю, мне нужна логика рекурсии, но я действительно не знаю, с чего начать.

Спасибо !

Матье


person tjeuten    schedule 14.09.2010    source источник


Ответы (2)


Использование CTE будет работать.

Тестовый скрипт

DECLARE @IDs TABLE (
  FromID INTEGER
  , ToID INTEGER
)

INSERT INTO @IDs
SELECT           1, 2 
UNION ALL SELECT 2, 3
UNION ALL SELECT 3, 4

Выражение SQL

;WITH q AS (
    SELECT  FromID, ToID
    FROM    @IDs
    UNION ALL 
    SELECT  q.FromID, u.ToID
    FROM    q
            INNER JOIN @IDs u ON u.FromID = q.ToID
)
SELECT  FromID, MAX(ToID)
FROM    q
WHERE   FromID = 1
GROUP BY
        FromID           
person Lieven Keersmaekers    schedule 14.09.2010
comment
Протестировал это, и почти там, за исключением того, что MAX (ToID) не будет работать, потому что идентификатор назначения, с которым выполняется слияние, не обязательно больше, чем предыдущий идентификатор назначения в той же цепочке... Таким образом, идентификатор 1 может объединиться с 3, и 3 может затем объединиться с 2, например - person tjeuten; 14.09.2010
comment
Можно исправить это, добавив временную метку в информацию о слиянии и выбрав метод описания первого заказа по дате. Но мне было интересно, можно ли это сделать без отметки времени - person tjeuten; 14.09.2010

Если это сработает для вас, дайте Ливену принятый ответ, поскольку он основан на его коде.

;WITH q AS (
    SELECT  1 AS LEVEL, FromID, ToID
    FROM    @IDs
    WHERE FromID=1
    UNION ALL 
    SELECT  LEVEL + 1, q.FromID, u.ToID
    FROM    q
            INNER JOIN @IDs u ON u.FromID = q.ToID
)

SELECT TOP 1 ToID
 FROM q
ORDER BY LEVEL DESC
person Martin Smith    schedule 14.09.2010