选择SQL Server中相同表关系中的所有父项或子项

时间:2014-01-20 09:24:27

标签: sql sql-server tsql select sql-server-2012

SQL开发人员,我有一个计划不周的数据库作为了解SQL Server 2012的重要任务。

所以,有表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的一个元素的所有“父+祖父母+等”?

  2. 如何选择DIST的一个元素的所有“儿子+孙子+等”?

  3. 我读过有关CTE的解决方案,但我没有元素根,我甚至无法理解如何使用CTE。

    请帮忙!

    感谢。

4 个答案:

答案 0 :(得分:24)

我遇到了这个问题,我通过这种方式解决了问题

 --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.My英语不好。

答案 1 :(得分:1)

这是一个递归查询,为您提供元素的所有祖先和所有后代。根据情况一起使用或分开使用。替换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

答案 2 :(得分:0)

我已经创建了一个函数来查找特定孩子的父母,你必须传递孩子的Id。

这将以逗号分隔的字符串形式返回父列表。 试试这个,如果它适合你。

我假设parent_key with null value是root。

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

答案 3 :(得分:0)

我不认为它可以在一个选择中完成,所以你可以选择所有的父母,祖父母,....一种方法是将elem表连接到自己,这取决于你做多少级别的连接,你会得到多少个孩子,孙子。

解决方案可以像这样思考(对于第二种情况)

这将选择所有父母,孩子和孙子

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'风格但是oposite'parentkey = key'的表。