【问题标题】:How to select parents and children rows in SQL Server如何在 SQL Server 中选择父行和子行
【发布时间】:2013-03-04 11:51:08
【问题描述】:

我想从下表中选择与 user_id 53(父母和孩子)相关的所有项目。应该是:1、2、4、8、9。

my_table
--------------------------------------------
id    parent_id   user_id   sequence   depth
--------------------------------------------
1     null        50        1          1
2     1           52        1.2        2
3     1           52        1.3        2
4     2           53        1.2.4      3
5     2           52        1.2.5      3
6     3           52        1.3.6      3
7     3           51        1.3.7      3
8     4           51        1.2.4.8    4
9     4           51        1.2.4.9    4

使用 CTE,我可以选择所有孩子或父母,但我不能只用一个查询来选择孩子和父母。下面是我用来选择孩子的 cte。

项目和子项

with cte as (
    select t.id, t.parent_id, t.user_id 
    from my_table t 
    where t.user_id=53

    union all

    select t.id, t.parent_id, t.user_id 
    from my_table t
    inner join cte c on (c.parent_id=t.id)
)
select t.* from cte t;

项目和父母

with cte as (
    select t.id, t.parent_id, t.user_id 
    from my_table t 
    where t.user_id=53

    union all

    select t.id, t.parent_id, t.user_id 
    from my_table t
    inner join cte c on (c.id=t.parent_id)
)
select t.* from cte t;

谢谢。

【问题讨论】:

    标签: sql sql-server select common-table-expression


    【解决方案1】:

    拥有序列非常方便。父母有一个与您正在寻找的初始子集相匹配的序列。孩子们也是如此,但反过来。

    以下内容接近您想要的:

    select mt.*
    from (select sequence from my_table where USER_ID = 53) theone join
         my_table mt
         on mt.sequence like theone.sequence+ '%' or
            theone.sequence like mt.sequence + '%'
    

    但是,例如,您必须小心 10 匹配 1。所以,让我们在适当的地方添加一个额外的句号:

    select mt.*
    from (select sequence from my_table where USER_ID = 53) theone join
         my_table mt
         on mt.sequence like theone.sequence+ '.%' or
            theone.sequence like mt.sequence + '.%'
    

    【讨论】:

    • 很好的解决方案,戈登。您刚刚忘记添加 user_id=53 的行:“在 mt.id=theone.id or mt.sequence like theone.sequence+ '.%' or theone.sequence like mt.sequence + '.%'”跨度>
    • 像你一样思考,我们也可以使用exists:select mt.* from my_table mt where exists(select id from my_table theone where user_id=53 and (mt.id=theone.id or mt .sequence like theone.sequence+ '.%' 或 theone.sequence like mt.sequence + '.%'))
    • @DiogoArenhart 。 . .是的,我认为类似的方法也可以。
    【解决方案2】:

    这里的问题是,您需要一个递归 SELECT。没有为此类查询创建 DBMS。但这当然是可能的。

    SELECT t1.* FROM Table1 t1 WHERE user_id = 53
    
    UNION ALL
    
    SELECT t2.* FROM Table1 t1, Table1 t2
    WHERE
      (t1.id = t2.parent_id OR t1.parent_id = t2.id) AND t1.user_id = 53
    

    此查询将为您提供每个 1 级亲属。

    对于递归 SELECT,请看这里:Recursive select in SQL


    您的查询的解决方案在这里:http://sqlfiddle.com/#!6/e1542/10/0

    with cte as (
        select t.id, t.parent_id, t.user_id 
        from Table1 t 
        where t.user_id=53
    ),
    
    cte1 as (
        select t.id, t.parent_id, t.user_id 
        from cte t
    
        union all
    
        select t.id, t.parent_id, t.user_id 
        from Table1 t
        inner join cte1 c on (c.parent_id=t.id)
    ),
    
    cte2 as (
        select t.id, t.parent_id, t.user_id 
        from cte t
    
        union all
    
        select t.id, t.parent_id, t.user_id 
        from Table1 t
        inner join cte2 c on (c.id=t.parent_id)
    )
    
    select t.* from cte1 t
    
    UNION
    
    select t.* from cte2 t
    

    【讨论】:

    • CTE 可以用作递归查询。 Diogo 使用的两个查询 递归的。
    • 是的,我知道。但这对数据库来说很累;)..我还用 sql fiddle 发布了解决方案。 ...如果您阅读了我回答的前 3 句话,您会看到 But it's of course possible.
    • 但您还写道:“DBMS 不是为这样的查询而制作的”这不是真的。第一个声明并不符合 Diogo 的要求(抱歉,我无法撤销我的反对票 - 我只会得到“没有锁定”)。
    • 绝对不适合这种操作。如果树层次结构变大,它可能会导致成百上千的单个 SELECT 查询(每个都包括一个 JOIN)。
    • 递归存储过程的效率会降低。这取决于 DBMS。 Oracle 的递归处理速度极快。
    【解决方案3】:
    declare @Rownumber int;
    CREATE TABLE #GetSeqUser (
        RowNumber int,
        UserId int,
    )
    INSERT INTO #GetSeqUser Select ROW_NUMBER() OVER(ORDER BY EmpId ASC) AS ROWNUMBER, EmpId FROM  dbo.TreeSystem
    set @Rownumber = (select ROWNUMBER from #GetSeqUser where UserId = 3 )
    set @Rownumber = @Rownumber + 1
    select UserId from #GetSeqUser where ROWNUMBER = @Rownumber
    

    【讨论】:

    • 您好,感谢您提供代码 sn-p。如果您能评论它是如何解决 OP 的问题的,那就太好了,这样我们都可以从中学习!
    【解决方案4】:
    declare @Rownumber int;
    CREATE TABLE #GetSeqUser (
        RowNumber int,
        UserId int,
    )
    INSERT INTO #GetSeqUser Select ROW_NUMBER() OVER(ORDER BY EmpId ASC) AS ROWNUMBER, EmpId FROM  dbo.TreeSystem
    set @Rownumber = (select ROWNUMBER from #GetSeqUser where UserId = 3 )
    set @Rownumber = @Rownumber + 1
    select UserId from #GetSeqUser where ROWNUMBER = @Rownumber
    

    【讨论】:

    • 您好,感谢您提供代码 sn-p。如果您能评论它是如何解决 OP 的问题的,那就太好了,这样我们都可以从中学习!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多