SQL父子级和继承

时间:2019-02-16 08:17:45

标签: sql sql-server

我正在使用SQL Server 2016,希望有人可以帮助我解决这个问题。

我有一个表,其中包含相同记录及其属性之间的关系。这是一个示例表。

CREATE TABLE [Family] ([Id] Int NOT NULL, [Relation] VARCHAR(12), [Level] TinyInt,  [Shoes] VARCHAR(12), [Shirt] VARCHAR(12), [Coat] VARCHAR(12))

INSERT INTO [Family] ([Id], [Relation], [Level], [Shoes], [Shirt], [Coat])
   VALUES (1, 'Grandparent', 1, 'Blue', 'Brown', 'Green'),
          (1, 'Parent',2, 'Red', NULL, NULL),
          (1, 'Child', 3, NULL, 'Yellow', NULL),
          (2, 'Grandparent', 1, 'Purple', 'Grey', 'Blue'),
          (2, 'Parent',2, NULL, 'Brown', 'Green')
          (2, 'Child', 3, NULL, NULL, 'Yellow');

关键字段是ID和级别。规则是我希望能够选择并返回每个id的一行,其中该属性返回的是最高级别(不为null)的那一行。即,如果该值为null,则从下一个较低级别继承。

我希望我解释对了,所以结果看起来像这样:

Id          Shoes  Shirt  Coat
----------- ------ ------ ------
1           Red    Yellow Green
2           Purple Brown  Yellow

我已经尝试过使用ISNULL和函数的几种方法,但是它们最终变得一团糟并且运行缓慢。当然,我在这里发布的只是一个简单的示例,实际表将具有8-10个级别和20+列属性,并且我需要它在大型数据集上执行。

我四处寻找,没有发现真正匹配的东西,谢谢

2 个答案:

答案 0 :(得分:1)

我只需要尝试一下。
显然,DISTINCT是在像FIRST_VALUE这样的窗口函数之后处理的。

SELECT DISTINCT Id, 
 FIRST_VALUE(Shoes) OVER (PARTITION BY Id ORDER BY IIF(Shoes is null,0,Level) DESC) AS Shoes,
 FIRST_VALUE(Shirt) OVER (PARTITION BY Id ORDER BY IIF(Shirt is null,0,Level) DESC) AS Shirt,
 FIRST_VALUE(Coat)  OVER (PARTITION BY Id ORDER BY IIF(Coat is null,0,Level) DESC) AS Coat
FROM Family;

结果:

Id  Shoes   Shirt   Coat

1   Red     Yellow  Green
2   Purple  Brown   Yellow

上个月的测试 here

答案 1 :(得分:0)

想到的第一件事是下一个想法:

select f.Id,shoes.Shoes,shirt.Shirt,coat.Coat from [Family] f
left join (select top 1 with ties Id,Shoes from [Family] order by ROW_NUMBER() over (partition by Id order by case when Shoes is not null then [Level] else null end) desc) shoes
    on shoes.Id = f.Id
left join (select top 1 with ties Id,Shirt from [Family] order by ROW_NUMBER() over (partition by Id order by case when Shirt is not null then [Level] else null end) desc) shirt
    on shirt.Id = f.Id
left join (select top 1 with ties Id,Coat from [Family] order by ROW_NUMBER() over (partition by Id order by case when Coat is not null then [Level] else null end) desc) coat
    on coat.Id = f.Id
group by f.Id,shoes.Shoes,shirt.Shirt,coat.Coat
order by f.Id