web-dev-qa-db-de.com

Wählen Sie alle übergeordneten oder untergeordneten Elemente in derselben SQL Server-Beziehung aus

SQL-Entwickler, ich habe eine schlecht geplante Datenbank als Aufgabe, um viel über SQL Server 2012 zu lernen.

SO gibt es die Tabelle Elem:

+-----------+----+---+----------+------------+
|VERSION(PK)|NAME|KEY|PARENT_KEY|DIST_KEY(FK)|
+-----------+----+---+----------+------------+
|1          |a   |12 |NULL      |1           |
+-----------+----+---+----------+------------+
|2          |b   |13 |12        |1           |
+-----------+----+---+----------+------------+
|3          |c   |14 |13        |1           |
+-----------+----+---+----------+------------+
|4          |d   |15 |12        |1           |
+-----------+----+---+----------+------------+
|5          |e   |16 |NULL      |1           |
+-----------+----+---+----------+------------+
|6          |e   |17 |NULL      |2           |
+-----------+----+---+----------+------------+

Nach der Aktualisierung der Zeile muss der übergeordnete Schlüssel des Elements überprüft werden, damit das Element nicht selbstgroß oder etwas sein kann. 

Und wenn ich die Zeile lösche, muss ich alle Kinder und Kinder von Kindern usw. löschen.

Fragen sind:

  1. Wie kann ich alle "Eltern + Großeltern + usw." eines Elements von DIST auswählen?

  2. Wie kann ich alle "Söhne + Enkel + etc" eines Elements von DIST auswählen?

Ich habe über Lösungen mit CTE gelesen, aber ich habe keine Wurzel von Elementen und ich kann nicht einmal verstehen, wie ich CTE dann verwenden kann. 

Bitte helfen

Vielen Dank.

15
Khronos

Ich bin diesem Problem begegnet

 --all  "parent + grandparent + etc" @childID Replaced with the ID you need

with tbParent as
(
   select * from Elem where [KEY][email protected]
   union all
   select Elem.* from Elem  join tbParent  on Elem.[KEY]=tbParent.PARENT_KEY
)
 SELECT * FROM  tbParent
 --all "sons + grandsons + etc" @parentID Replaced with the ID you need

with tbsons as
(
  select * from Elem where [KEY][email protected]
  union all
  select Elem.* from Elem  join tbsons  on Elem.PARENT_KEY=tbsons.[KEY]
)
SELECT * FROM tbsons

PS.Mein Englisch ist nicht gut.

23
HunkHui

hier ist eine rekursive Abfrage, die alle Vorfahren und Nachkommen eines Elements enthält. Verwenden Sie diese zusammen oder trennen Sie sie je nach Situation. Ersetzen Sie die where-Klauseln, um den gewünschten Datensatz zu erhalten. In diesem Beispiel suche ich nach Schlüssel 13 (dies ist das Element mit name = b) und finde seinen Vorfahren 12/a und seinen Nachkommen 14/c.

with all_ancestors(relation, version, name, elem_key, parent_key, dist_key)
as 
(
  -- the record itself
  select 'self      ' as relation, self.version, self.name, self.elem_key, self.parent_key, self.dist_key
  from elem self
  where elem_key = 13
  union all
  -- all its ancestors found recursively
  select 'ancestor  ' as relation, parent.version, parent.name, parent.elem_key, parent.parent_key, parent.dist_key
  from elem parent
  join all_ancestors child on parent.elem_key = child.parent_key
)
, all_descendants(relation, version, name, elem_key, parent_key, dist_key)
as 
(
  -- the record itself
  select 'self      ' as relation, self.version, self.name, self.elem_key, self.parent_key, self.dist_key
  from elem self
  where elem_key = 13
  union all
  -- all its descendants found recursively
  select 'descendant' as relation, child.version, child.name, child.elem_key, child.parent_key, child.dist_key
  from elem child
  join all_descendants parent on parent.elem_key = child.parent_key
)
select * from all_ancestors
union
select * from all_descendants
order by elem_key
;

Hier ist die SQL-Geige: http://sqlfiddle.com/#!6/617ee/28 .

1

Ich habe eine Funktion zum Finden der Eltern eines bestimmten Kindes erstellt, bei der Sie die ID des Kindes übergeben müssen.

Dadurch wird die Liste der Eltern als durch Kommas getrennte Zeichenfolge zurückgegeben. Versuchen Sie dies, wenn es für Sie funktioniert.

Ich gehe davon aus, dass der parent_key with null value root ist.

CREATE FUNCTION checkParent(@childId INT)
RETURNS VARCHAR(MAX)
AS
BEGIN
    DECLARE @parentId VARCHAR(MAX) = NULL
    DECLARE @parentKey INT = null
    SET @parentId = (SELECT parent_key FROM Elem WHERE [KEY] = @childId)

    WHILE(@parentKey IS NOT NULL)
    begin
        SET @parentId = @parentId +  ', ' + (SELECT parent_key FROM Elem WHERE [KEY] = @parentId)
        SET @parentKey = (SELECT parent_key FROM Elem WHERE [KEY] = @parentId)
    END
    RETURN @parentId
END
GO
0
Suraj Shrestha

Ich glaube nicht, dass dies in einem einzigen Fall in einem einzigen Fall ausgeführt werden kann, sodass Sie alle Eltern, Großeltern, ... auswählen können. Eine Möglichkeit, dies zu tun, besteht darin, den elem-Tisch mit sich selbst zu verbinden, und es hängt davon ab, wie viele Ebenen Sie beitreten, wie viele Kinder, Enkelkinder.

Die Lösung kann so etwas sein (für den zweiten Fall)

dadurch werden alle Eltern, Kinder und Enkelkinder ausgewählt

Select 
parent.key as parent_key,
child.key as child_key,
grandchild.key as grandchild_key 
from elem parent 
join elem child on (elem.key=child.parentkey)
join elem grandchild on (child.key=grandchild.parentkey)
where parent.parentkey is null; -- this make you sure that first level will be parents

lösung für den ersten Fall ist nur, dass Sie Tabellen nicht im Stil von 'key = parentkey', sondern gegenüber 'parentkey = key' verbinden. 

0
Ján Srniček