2016-07-05 2 views
0

Так у меня есть набор таблиц вдоль линий следующегорекурсия в SQL

cables: 
id (integer) | name (char) 

knots: 
id (integer) | name (char) 

cableKnotAttachments: 
id (integer) | sourceCableId (integer) | targetKnotId (integer) 

cableCableAttachments: 
id (integer) | sourceCableId (integer) | targetCableId (integer) 

Если Cable может быть присоединен к нескольким другим Cable с, а также несколько Knot сек и Knot может быть присоединен к несколько Cable s.

Учитывая, что Cables.Id, мне нужно найти все Knots, которые находятся в пределах этого Cable детей. Мы говорим, что узел является ребенком Cable, если он либо непосредственно прикреплен, либо является ребенком любого Cable, который прикреплен к Cable.

Моя попытка до сих пор выглядит следующим образом:

SELECT cableKnotAttachments.targetKnotId 
    FROM cableKnotAttachments 
    WHERE cableKnotAttachments.sourceCableId = 1 

UNION 

SELECT cableKnotAttachments.targetKnotId 
    FROM cableKnotAttachments 
    INNER JOIN cableCableAttachments 
    ON cableKnotAttachments.sourceCableId = cableCableAttachments.targetCableId 
    WHERE cableCableAttachments.sourceCableId = 1; 

В псевдо-коде, что было бы неплохо:

getDirectlyAttachedKnots(cableId) { 
    return knots directly attached to cableId 
} 

getDirectlyAttachedCables(cableId) { 
    return cables directly attached to cableId 
} 

getAllChildKnots(cableId) { 
    knots = getDirectlyAttachedKnots(cableId) 

    for attachedCableId in getDirectlyAttachedCables(cableId) { 
     knots += getAllChildKnots(attachedCableId) 
    } 

    return knots; 
} 

Но это распространяется только на один уровень рекурсии (без меня просто повторять, что ad nauseam).

Есть ли простой способ сделать это в SQL Server. Можно предположить, что это нецелесообразно проверять все Knot s в виде обратной проверки.

Редактировать: Добавление некоторых выборочных данных для процветания. Предполагая, что у нас есть Cables с id s {1, 2, ..., 4}; и Knots с id s {1, 2, ..., 9}:

cableCableAttachments: 
id | sourceCableId | targetCableId 
1 | 1    | 2 
2 | 3    | 2 
3 | 2    | 4 

cableKnotAttachments: 
id | sourceCableId | targetKnotId 
1 | 1    | 2 
2 | 1    | 3 
3 | 2    | 4 
4 | 3    | 5 
5 | 3    | 6 
6 | 3    | 7 
7 | 4    | 1 
8 | 4    | 2 
9 | 4    | 3 

В каком контексте мы имеем:

cableId | childKnots 
1  | 2, 3, 4, 1 
2  | 4, 1, 2, 3 
3  | 5, 6, 7, 4 
4  | 1, 2, 3 
+1

Возможный дубликат [Sql сервера КТР и пример рекурсии] (http://stackoverflow.com/questions/14274942/sql-server-cte-and -recursion-example) –

+0

Похоже, вам понадобится как минимум 1 cte, чтобы найти все кабели, а затем присоединиться, чтобы получить все узлы. Примеры данных были бы очень полезны здесь – Matt

ответ

1

Этот ответ очень вероятно, потребуется некоторая работа, как это действительно трудно концептуализировать INNER JOIN на рекурсивном КТР без тестовых данных и зная, как ваши отношения хранятся, в частности, в кабельных устройствах. Но это hopeuflly даст вам представление о том, что попробовать:

;WITH cteRecursiveCables AS (
    SELECT 
     id AS startingAncestorId 
     ,id as ancestorId 
     ,id AS cableId 
     ,1 AS recursionLevel 
    FROM 
     Cables 
    WHERE id = 2 -- For example 

    UNION ALL 

    SELECT 
     startingAncestorId = cte.startingAncestorId 
     ,ancestorId = cte.CableId 
     ,cableId = att.targetCableId 
     ,recursionLevel = cte.recursionLevel + 1 
    FROM 
     cableCableAttachments att 
     INNER JOIN cteRecursiveCables cte 
     ON a.sourceCableId = cte.cableId 
) 

SELECT att.targetKnotId 
FROM 
    cteRecursiveCables cte 
    INNER JOIN cableKnotAttachments att 
    ON cte.cableId = att.sourceCableId 
; 
+0

К сожалению, у меня нет компьютера с SQL Server, установленного для тестирования этих данных (на текущем компьютере есть только SQLite, который, насколько мне известно, не имеет возможности подтвердить это поведение); однако это похоже на то, с чем я должен работать. Спасибо за ваше время; Я проверю, что подобное решение работает позже сегодня, а затем отметьте это как принятый ответ, если это так. – user2478398

+0

Благодарим вас за помощь; Я представил небольшое редактирование версии, которая работала для меня, но изменения были относительно незначительными. Принимается в качестве соответствующего ответа; еще раз спасибо за то, что нашли время ответить. – user2478398

+1

yep Я только что просмотрел редактирование, большинство из которых были просто желаемыми псевдонимами. Я изменил одну часть вашего редактирования. вы можете ограничить рекурсию необходимой, поместив оператор where в таблицу привязки (первая таблица в cte). ИТ будет работать быстрее и не будет обрабатывать записи, которые вы не будете использовать. Рад, что это сработало! – Matt