Firebird SQL Query для поиска петли в данных

У меня проблемы с написанием SQL-запроса, чтобы найти "цикл данных" в моей таблице Firebird.

Очень сложно объяснить ситуацию, поэтому я приведу пример:

Table: Explosion    

Stockcode   | IngredientStockcode
----------------------------------
001         | 010 
001         | 011
001         | 012

010         | 011
010         | 013
010         | 014    

012         | 013
012         | 015
012         | 001 <-- This causes a loop in my data. Stockcode 001 has an 
                      ingredient of 012 and stockcode 012 has 001 as 
                      an ingredient.

013         | 014
013         | 015
013         | 001 <-- This also causes a loop in my data. 013 is part of (an
                      ingredient of) 010. 010 is also an ingredient of 001. 001
                      cannot then also be an ingredient of 013.

Мне нужно написать запрос, чтобы определить эти "петли" в данных. Любая помощь будет оценена.

Это должен быть сложный запрос с объединениями. Я уже пробовал что-то подобное ниже, и я думаю, что я на правильном пути..

select * FROM explosion x1
WHERE EXISTS ( SELECT 1 FROM Explosion x2
               where exists ( SELECT 1 FROM Explosion x3 where
                              x3.ingredientStockcode = x1.Stockcode
                              AND x1.RDB$DB_KEY < x3.RDB$DB_KEY)
and x1.ingredientStockcode = x2.Stockcode
AND x1.RDB$DB_KEY < x2.RDB$DB_KEY)

2 ответа

Здесь у вас типичная проблема с графиком / деревом.

Боюсь, что один запрос не решит вашу проблему. Вам понадобится цикл, чтобы пройти каждое дерево.

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

Второй вариант более естествен для такого рода данных, потому что что-то всегда пригодно для создания чего-то более сложного.

Вы можете искать в Google алгоритмы для деревьев в SQL.

успех

Я не уверен насчет синтаксиса Firebird SQL, но этот общий запрос SQL поможет вам:

select *  
from Explosion e1
inner join Explosion e2 
        on e1.Stockcode = e2.IngredientStockcode
       and e1.IngredientStockcode = e2.Stockcode

РЕДАКТИРОВАТЬ

Была быстрая проверка, и документация, кажется, предполагает, что вышеупомянутое будет работать. Однако, на всякий случай, альтернативный синтаксис:

select *  
  from Explosion e1, Explosion e2
 where e1.Stockcode = e2.IngredientStockcode
   and e1.IngredientStockcode = e2.Stockcode
Другие вопросы по тегам