web-dev-qa-db-ja.com

同じテーブルリレーションSQL Server内のすべての親または子を選択します

SQL開発者、私はSQL Server 2012について多くを学ぶためのタスクとして、よく計画されていないデータベースを持っています。

SO、テーブル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           |
+-----------+----+---+----------+------------+

行を更新した後、要素の親キーをチェックして、要素が自己成長することを許可しないようにする必要があります。

行を削除するときは、すべての子と子の子などを削除する必要があります。

質問は:

  1. DISTの1つの要素の「親+祖父母+など」をすべて選択するにはどうすればよいですか?

  2. DISTの1つの要素の「息子+孫+など」をすべて選択するにはどうすればよいですか?

CTEを使用したソリューションについて読みましたが、要素の根本がなく、CTEをどのように使用できるかさえ理解できません。

助けてください!

ありがとう。

17
Khronos

私はこの問題に遭遇しました、この方法で問題を解決しました

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

with tbParent as
(
   select * from Elem where [KEY]=@childID
   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]=@parentID
  union all
  select Elem.* from Elem  join tbsons  on Elem.PARENT_KEY=tbsons.[KEY]
)
SELECT * FROM tbsons

PS。私の英語は下手です。

25
HunkHui

これは、要素のすべての祖先とすべての子孫の両方を提供する再帰クエリです。状況に応じて、併用または分離してご利用ください。 where句を置き換えて、目的のレコードを取得します。この例では、キー13(これは名前= bの要素です)を探して、その祖先12/aとその子孫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
;

これがSQLフィドルです: http://sqlfiddle.com/#!6/617ee/28

1

子のIDを渡す必要がある特定の子の親を見つけるための関数を作成しました。

これにより、親のリストがカンマ区切りの文字列として返されます。それがあなたのために働くなら、これを試してください。

parent_key with null valueはルートです。

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

私はそれがすべての親、祖父母、...を選択できるように、それが全体のケースで1つの選択で行うことができるとは思いません。それを行う方法の1つは、elemテーブルを自分自身に結合することです。それは、結合のレベルの数に依存します。そのレベルの子、孫は、取得します。

解決策はこのように考えることができます(2番目の場合)

これにより、すべての親、子、孫が選択されます

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

最初のケースの解決策は、「key = parentkey」のスタイルではなく「parentkey = key」の反対のテーブルを接続することです。

0
Ján Srniček