【问题标题】:Get nth level on self-referencing table在自引用表上获得第 n 级
【发布时间】:2017-04-13 08:00:21
【问题描述】:

我有一个最多有 5 个级别的自引用表

groupid   | parentid  | detail
--------- | --------- | ---------
Group A   | Highest   | nope 
Group B   | Group A   | i need this  
Highest   | NULL      | nope 
Group C   | Group B   | nope 
Group D   | Group C   | nope 

我有一个事务表,它在上面的表中查找 groupid 以检索其中 groupid = Group B 的详细值。事务表上 groupid 的值仅在 Group B 到 D 之间,并且永远不会更高.

txnid     | groupid   | desired   | desired
--------- | --------- | --------- | ---------
1         | Group D   | Group B   | i need this
2         | Group B   | Group B   | i need this
3         | Group C   | Group B   | i need this
4         | Group B   | Group B   | i need this

我的 T-SQL 脚本应该如何获得所需的列?我可以多次离开加入到自引用表中,直到 B 组我需要重新加入的时间不一致。

非常感谢任何想法!

【问题讨论】:

  • 为什么停在Group A 以及desired 列的目的是什么?
  • 你知道你的交易表上每个groupid的级别吗?
  • @TimBiegeleisen 它是公司级别的层次结构。例如:最高 - 公司,A 组 - 部门,B 组 - 部门,C 组 - 团队,D 组 - 个人。抱歉,如果它令人困惑,因为我必须掩盖实际的表示。在我的示例中,所需的列应采用部门的值。我需要将其存储在事务中,以便稍后在事务表中应用子集/行级权限
  • 你没有回答我的任何问题。由于没有其他人回答,我可能是正确的,您的问题不清楚。
  • @McNets 在上面的示例中,事务表最多有 3 个级别(B、C、D)。他们的价值观不高于 B 组

标签: sql sql-server


【解决方案1】:

我仍然不清楚你怎么知道哪个是 GROUP B,我想这是它的父级为空的记录。

create table org(groupid char(1), parentid char(1), details varchar(20));
insert into org values
('a', null, 'nope'),('b', 'a', 'I need this'),('c', 'b', 'nope'),('d', 'c', 'nope'),('e', 'd', 'nope');

create table trans(id int, groupid char(1));
insert into trans values
(1, 'b'),(2, 'c'),(3, 'c'),(4, 'd'),(5, 'e');
GO
10 行受影响
with all_levels as
(
    select     ob.groupid groupid_b, oc.groupid groupid_c, 
               od.groupid groupid_d, oe.groupid groupid_e, 
               ob.details
    from       org ob
    inner join org oc
    on         oc.parentid = ob.groupid
    inner join org od
    on         od.parentid = oc.groupid
    inner join org oe
    on         oe.parentid = od.groupid
    where      ob.parentid is not null
) select * from all_levels;

GO
groupid_b | groupid_c | groupid_d | groupid_e |细节 :-------- | :-------- | :-------- | :-------- | :---------- 乙 | c | d |电子|我需要这个
--= build a 4 levels row
with all_levels as
(
    select     ob.groupid groupid_b, oc.groupid groupid_c, 
               od.groupid groupid_d, oe.groupid groupid_e, 
               ob.details
    from       org ob
    inner join org oc
    on         oc.parentid = ob.groupid
    inner join org od
    on         od.parentid = oc.groupid
    inner join org oe
    on         oe.parentid = od.groupid
    where      ob.parentid is not null
) 
    --= no matter what groupid returns b group details
    , only_b as
    (
        select groupid_b as groupid, groupid_b, details from all_levels
        union all
        select groupid_c as groupid, groupid_b, details from all_levels
        union all
        select groupid_d as groupid, groupid_b, details from all_levels
        union all
        select groupid_e as groupid, groupid_b, details from all_levels
    )
    --= join with transactions table
    select     id, t.groupid, groupid_b, ob.details
    from       trans t
    inner join only_b ob
    on         ob.groupid = t.groupid;
GO
编号 |组ID | groupid_b |细节 -: | :-------- | :-------- | :---------- 1 |乙 |乙 |我需要这个 2 | c |乙 |我需要这个 3 | c |乙 |我需要这个 4 | d |乙 |我需要这个 5 |电子|乙 |我需要这个

dbfiddle here

您也可以处理递归函数,但我认为它在性能方面不会更好。

create function findDetails(@groupid char(1))
returns varchar(100)
as
begin
    declare @parentid char(1) = '1';
    declare @next_parentid char(1) = '1';
    declare @details varchar(100) = '';

    while @next_parentid is not null
    begin
        select     @details = org.details, @parentid = org.parentid, @next_parentid = op.parentid
        from       org
        inner join org op
        on         op.groupid = org.parentid
        where      org.groupid = @groupid

        set @groupid = @parentid;
    end

    return @details;
end
GO
select id, groupid, dbo.findDetails(groupid) as details_b
from   trans;
GO
编号 |组ID |细节_b -: | :-------- | :---------- 1 |乙 |我需要这个 2 | c |我需要这个 3 | c |我需要这个 4 | d |我需要这个 5 |电子|我需要这个

dbfiddle here

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-08-31
    • 2015-12-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多