【问题标题】:Select all parents or children in same table relation SQL Server选择同一表关系 SQL Server 中的所有父级或子级
【发布时间】:2014-02-09 09:37:12
【问题描述】:

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 的一个元素的所有“儿子 + 孙子 + 等”?

我阅读了有关 CTE 的解决方案,但我没有元素的根源,我什至无法理解如何使用 CTE。

请帮忙!

谢谢。

【问题讨论】:

  • 你确实有一个根:没有parent_key的项目
  • 我的意思是所有元素的根,但如果根可以是行 - 你是对的。已编辑。但我对 SQL 很陌生。我可以编写触发器,但根本无法制作简单的递归和其他循环/CTE 解决方案。所以拥有那个根仍然不能帮助我。

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


【解决方案1】:

我遇到过这个问题,我就是这样解决的

 --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.我的英文不好。

【讨论】:

  • 我使用了像你这样的联合来获得新的观点。我的观点有通行证(父母/孩子的名字/..)进行搜索。谢谢。
  • @HunkHui 很好的回答
【解决方案2】:

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

【讨论】:

  • 也可以,但不是那么简单。无论如何,谢谢,存储在知识中
【解决方案3】:

我创建了一个函数,用于查找特定孩子的父母,您必须在其中传递孩子的 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

【讨论】:

  • 父母的简单解决方案,但至少不是那么简单。谢谢回答。
【解决方案4】:

我不认为它可以在整个案例中一次选择完成,这样您就可以选择所有父母,祖父母,...。一种方法是自己加入 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”的样式,而是与“parentkey=key”相反的样式。

【讨论】:

  • 我想到了使用带有路径 + 级别的视图,其计算逻辑与我的问题的检查答案相同。所以通常你也可以帮助我。
  • 也许您可以在应用程序部分执行此操作,该功能将创建您在所需的多个级别上进行选择,因为您可以在不同的情况下需要不同的深度,因此无需每次都选择everythink .它会更快,从大型数据库(1000+表)的经验来看,在数据库级别上做每一个想法并不是每次都是一个好的解决方案。分页访问也可以解决在特定范围内(1-50、51-100 等)采用行号较小的查询
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多