【问题标题】:SQL - 1 Parent Table, 2 Child Tables - return single row for each row in the child tableSQL - 1 个父表,2 个子表 - 为子表中的每一行返回单行
【发布时间】:2023-04-03 13:01:01
【问题描述】:

表 A

  • 父母ID
  • 姓名

表 B

  • BKey
  • 父母ID
  • 描述B

表 C

  • CKey
  • 父母ID
  • DescC

我需要为 B/A 中与父 id 匹配的每个组合数据行返回 1 行,如果其中一个子表的行数多于另一个,则该描述的行应返回空值。

例如,如果数据如下

表 A

1   FirstParent
2   Second Parent

表 B

1   1   BDesc1
2   1   BDesc2
3   2   P2BDesc1

表 C

1   1   CDesc1
2   2   P2CDesc1
3   2   P2CDesc2

如果我根据FirstParent检索,结果应该是:

1   FirstParent   BDesc1   CDesc1
1   FirstParent   BDesc2   NULL

如果我根据SecondParent检索,结果应该是:

2   SecondParent   P2BDesc1   P2CDesc1
2   SecondParent   NULL       P2CDesc2

有没有不用工会就可以做到这一点?

【问题讨论】:

    标签: sql join union


    【解决方案1】:
    declare @ParentID int
    set @ParentID = 1
    
    select a.name,
           bc.descb,
           bc.descc
    from   TableA as a
      cross join (select b.descb,
                         c.descc
                  from   (select *,
                                 row_number() over(order by b.bkey) as rn
                          from   TableB as b
                          where  b.parentid = @parentid) as b
                    full outer join 
                         (select *,
                                 row_number() over(order by c.ckey) as rn
                          from   TableC as c
                          where  c.parentid = @parentid) as c
                      on b.rn = c.rn) as bc
    where  a.parentid = @parentid  
    

    在这里试试:https://data.stackexchange.com/stackoverflow/qt/112538/

    编辑:使用ExternalKey查询多个ParentID的版本

    建议的索引:

    create index IX_B_ParentID on TableB(ParentID) include (DescB)
    create index IX_C_ParentID on TableC(ParentID) include (DescC)
    

    我会创建一个表变量来保存与 ExternalKey 匹配的 ParentID,然后在查询中使用它而不是 TableA。

    declare @ExternalKey int = 1
    
    declare @T table(ParentID int primary key, Name varchar(20))
    insert into @T (ParentID, Name)
    select ParentID, NAme
    from TableA
    where ExternalKey = @ExternalKey
    
    
    select a.name,
           bc.descb,
           bc.descc
    from   @T as a
      inner join (select b.descb,
                         c.descc,
                         coalesce(b.ParentID, c.ParentID) as ParentID
                  from   (select b.ParentID,
                                 b.DescB,
                                 row_number() over(partition by b.ParentID order by b.bkey) as rn
                          from   TableB as b
                          where  b.parentid in (select ParentID from @T)) as b
                    full outer join
                         (select c.ParentID,
                                 c.DescC,
                                 row_number() over(partition by c.ParentID order by c.ckey) as rn
                          from   TableC as c
                          where  c.parentid in (select ParentID from @T)) as c
                      on b.rn = c.rn and
                         b.ParentID = c.ParentID) as bc
        on a.ParentID = bc.ParentID
    

    【讨论】:

    • 我们对问题的理解方式不同,您的解决方案完全有效。 +1。我认为应该在不使用联合的情况下组合整个结果。但它也可能是 OP 希望在没有联合的情况下检索每个 A.parentID 的子结果。
    • 这回答了我提出的问题。所以,我会把它标记为已回答。但是,我确实简化了一点。此外,在父表上,a 是一列 ExternalKey,我通常会通过外部键拉取,因此它必须根据外部键检索具有多个 parentid 的结果集,并且在更改示例时我在从表中引用 parentid 时遇到问题。
    • @leifre - 修改@t-clausen.dk 提供的答案以满足您的要求会更容易。只需在主查询中添加 where 子句。 where a.ExternalKey = SomeValue.
    • 它更像:表 A - ParentID、Name、ExternalKeyID 然后我会将 externalkeyid 放在 where 子句中
    • @leifre - 是的 :) 我对此进行了编辑。你显然看到了我的第一个版本。
    【解决方案2】:

    您可以分两步实现它:

    1) 计算每个子表的记录数。

    2) 根据第一步的记录数加入第一个或第二个表

    select a.ParentId, a.Name, b.DescB, c.DescC
    from (
        select ParentId, (select count(*) from b where a.ParentId = b.ParentId) as cntB,
        (select count(*) from c where a.ParentId = b.ParentId) as cntC
    from a
    left join b cntB >= cntC and a.ParentId = b.ParentId
    left join c cntB < cntC and a.ParentId = c.ParentId
    

    【讨论】:

    • 我试图让这个工作,但在几个错误的语法后放弃了。
    • 虽然想法很有趣,但没想到会采用这种方法
    【解决方案3】:

    我真的希望这是 MSSQL 问题

    declare @a table(
    ParentID int,
    Name varchar(15))
    
    declare @b table(
    BKey int,
    ParentID int, 
    DescB varchar(10))
    
    
    declare @c table(
    CKey int,
    ParentID int,
    DescC varchar(10))
    
    insert @a values (1,'FirstParent')
    insert @a values (2,'SecondParent')
    
    insert @b values(1, 1, 'BDesc1')
    insert @b values(2, 1, 'BDesc2')
    insert @b values(3, 2, 'P2BDesc1') 
    
    insert @c values(1, 1, 'CDesc1')
    insert @c values(2, 2, 'P2CDesc1')
    insert @c values(3, 2, 'P2CDesc2')
    
    ;with b as
    (
        select DescB, ParentID, row_number() over (partition by parentid order by DescB) rn from @b
    ),
    c as
    (
        select DescC, ParentID, row_number() over (partition by parentid order by DescC) rn from @c
    ), 
    d as (
        select DescB, DescC, coalesce(b.parentid, c.parentid) parentid from b
        full outer join c
        on c.parentid = b.parentid and c.rn = b.rn
    )
    select a.ParentID, a.Name, d.DescB, d.DescC from @a a
    join d
    on a.parentid = d.parentid
    order by 1
    

    在这里试试: https://data.stackexchange.com/stackoverflow/q/112537/

    【讨论】:

    • Otroligt :) 这太多了。等同于“Try here”链接。 +1。 49 秒后。
    • @MikaelEriksson 很抱歉,下次你在丹麦的时候我会请你喝啤酒。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多