2012-12-12 12 views
5

Ich habe selbständige Entitäten (a) in meiner Datenbank, die von einer anderen Entität (b) referenziert werden, und eine bestimmte (b) Entität gegeben, muss ich alle (a) Entitäten, die benötigt werden. Dies sind viele zu viele Zuordnungen, daher habe ich eine separate Zuordnungstabelle. Ich denke, eine rekursive Select mit einem CTE ist meine beste Wette, aber ich stoße auf ein Problem:T-SQL Rekursive Wählen Kreisförmige Abhängigkeit

This Fiddle veranschaulicht mein Problem. Wenn ein Benutzer einen Zirkelverweis eingibt, wird das rekursive select zu einem quietschenden Halt. Ich habe mir das Gehirn kaputt gemacht, um einen Weg zu finden, das zu beheben. Es sollte beachtet werden, dass, obwohl ich Fremdschlüssel in die Geige eingeführt habe, Fremdschlüssel von dem System, das ich verwende, nicht wirklich geehrt werden (langwieriges Argument mit den Datenbankadministratoren) - ich habe sie eingeführt, um den Datenfluss klarer zu machen.

Die rekursive Abfrage, für diejenigen, die nicht wollen, auf der Geige durch klicken:

WITH recur(objID) AS (
    SELECT usesObjID 
     FROM #otherObj 
     WHERE otherObjID = 1 
    UNION ALL 
    SELECT slaveObjID 
     FROM #objMap 
      INNER JOIN recur 
       on #objMap.masterObjID = recur.objID 
)SELECT objID from recur 

Any da draußen Ideen? Dieser Entwurf ist nicht in Produktion, daher kann ich das Schema etwas ändern, aber ich möchte nicht darauf angewiesen sein, beim Einfügen Zirkelreferenzen zu entdecken, außer es kann von T-SQL gemacht werden.

+0

nie diese fxn verwendet, aber würde man einfach nicht sagen, 'auf objMap.masterObjID = recur.objID und recur.objID <> # otherobj.usesObjID'? oder ist das nicht möglich? – Beth

Antwort

8

Es ist möglich, die MAXRECURSION des CTE zu setzen, die die Endlosschleife verhindert, aber Sie werden immer noch merkwürdige Ergebnisse erhalten, da die Abfrage in der Schleife weiterläuft, bis die maximale Rekursion erreicht ist.

Die Herausforderung besteht darin, dass die Schleife mehrere Schritte umfasst. Sie können also nicht nur das unmittelbare übergeordnete Element des untergeordneten Elements überprüfen, um festzustellen, ob Sie sich in einer Schleife befinden.

Eine Möglichkeit, dies zu umgehen, wäre das Hinzufügen einer zusätzlichen Spalte zum CTE ... Diese neue Spalte, tree, verfolgt alle bisher enthaltenen IDs und stoppt, wenn sich eine ID wiederholt.

WITH recur(objID, Tree) AS (
    SELECT 
     usesObjID, 
     CAST(',' + CAST(usesObjID AS VARCHAR) + ',' AS VARCHAR) AS Tree 
    FROM otherObj 
    WHERE otherObjID = 1 
    UNION ALL 
    SELECT 
     slaveObjID, 
     CAST(recur.Tree + CAST(slaveObjID AS VARCHAR) + ',' AS VARCHAR) AS Tree 
    FROM objMap 
     INNER JOIN recur 
      ON objMap.masterObjID = recur.objID 
    WHERE recur.Tree NOT LIKE '%,' + CAST(slaveObjID AS VARCHAR) + ',%' 
)SELECT objID from recur 

Sql Fiddle Link

+0

Das ist großartig! Glaubst du, dass das auch funktionieren wird, wenn es ein Viel-zu-viele-Mapping von otherObj zu Obj ist? (Erneut eine andere Mapping-Tabelle) – FrankieTheKneeMan

+0

@FrankieTheKneeMan Ich denke, das wird auch funktionieren. Im Grunde genommen würden Sie nur die IDs verfolgen, mit denen Sie bisher verbunden waren, und aufhören, wenn Sie ein Duplikat sehen. –

+0

http://sqlfiddle.com/#!3/c1e62/3 <- Ich vertraue Benutzern nicht. Wenn sie die Struktur völlig verdirbt, kann ich dieses Ergebnis erhalten. Ich könnte ein distinct verwenden, um unterschiedliche Werte zu erhalten (ein Start auf jeden Fall), aber gibt es einen besseren Weg, dies zu tun? – FrankieTheKneeMan

Verwandte Themen