2010-11-29 39 views
1

J'ai des difficultés à écrire une requête SQL pour trouver une "boucle" de données dans ma table Firebird.Firebird SQL Requête pour trouver une boucle dans les données

Il est très difficile d'expliquer la situation, donc je vais plutôt donner un exemple:

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. 

Je dois écrire une requête pour identifier ces « boucles » dans les données. Toute aide serait appréciée.

Cela devrait être une requête complexe avec des jointures. Je l'ai déjà essayé quelque chose comme ça ci-dessous et je pense que je pourrais être sur la bonne voie ..

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) 
+0

@Delpiguy: Si vous avez un moyen de déterminer les matériaux premiers ** ** dans votre stock, vous pouvez vérifier rapidement une requête récursive, mais on ne sait pas, de ce que vous publiez si vous avoir un moyen dans votre structure de le déterminer dans une requête, pas à partir de la table d'explosion affichée. – jachguate

Répondre

1

Je ne suis pas sûr de la firebird syntaxe SQL, mais cette requête SQL générique Shold vous aider:

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

EDIT

Had une vérification rapide et la documentation semble suggérer fonctionnera ci-dessus. Cependant, juste au cas où, une syntaxe alternative est:

select * 
    from Explosion e1, Explosion e2 
where e1.Stockcode = e2.IngredientStockcode 
    and e1.IngredientStockcode = e2.Stockcode 
+0

Merci pour votre réponse rapide James, mais cela ne fonctionne pas. e1.Stockcode = e2.IngredientStockcode et e2.IngredientStockcode = e1.Stockcode est exactement la même déclaration. –

+0

Désolé, je l'ai embrouillé. Échangez l'e2 et e1 sur la dernière ligne –

+0

Désolé, mais cela ne fonctionne toujours pas. –

2

Vous avez ici un problème typique de graphe/arbre.

Je crains qu'une seule requête ne puisse résoudre votre problème. Vous aurez besoin d'une boucle pour traverser chaque arbre.

Mais vous avez un autre problème, vous ne pouvez pas facilement sélectionner les nœuds racine. Vous devrez donc soit marquer les nœuds de la racine, soit traverser vos arbres en bas (à commencer par les ingrédients de base qui n'ont pas d'autres ingrédients).

La deuxième option est plus naturelle pour ce type de données car quelque chose est toujours utilisable pour créer quelque chose de plus complexe.

Vous pouvez rechercher des algoritmes pour les arbres dans Google.

Succès

+0

Il peut être résolu facilement dans une requête en utilisant un CTE, mais je ne sais pas si Firebird les supporte – smirkingman