根据用户定义的层次结构选择值

时间:2019-06-11 09:42:05

标签: sql sql-server

我试图根据用户定义的层次结构选择值。 此层次结构未存储在系统上。

示例层次结构: 常规>专业>招聘

级别表(不一定顺序!)

+-----------+------------+
| ContactID | CategoryID |
+-----------+------------+
|         1 | Recruit    |
|         1 | Major      |
|         2 | Recruit    |
|         3 | Major      |
|         3 | General    |
|         3 | Recruit    |
+-----------+------------+

输出:

+-----------+------------+
| ContactID | CategoryID |
+-----------+------------+
|         1 | Major      |
|         2 | Recruit    |
|         3 | General    |
+-----------+------------+

工作样本方法:

select ContactID, 
case 
when "General" in (select CategoryID from Level l1 where l.ContactID = l1.ContactID) then "General"
when "Major" in (select CategoryID from Level l1 where l.ContactID = l1.ContactID) then "Major"
when "Recruit" in (select CategoryID from Level l1 where l.ContactID = l1.ContactID) then "Recruit"
from Level l

有没有更有效的方法?实际数据在层次结构和许多记录中有30个级别。

使用Microsoft SQL Server,

谢谢

编辑:(感谢您的帮助!) 理想的解决方案还排除未包含在已定义层次结构中的记录。

例如,我们不需要显示用户5,因为他们没有有效的类别,用户4应该列为“招聘”。

+-----------+------------+
| ContactID | CategoryID |
+-----------+------------+
|         1 | Recruit    |
|         1 | Major      |
|         2 | Recruit    |
|         3 | Major      |
|         3 | General    |
|         4 | Chef       |
|         4 | Matron     |
|         4 | Recruit    |
|         5 | Paratrooper|
+-----------+------------+

结果

+-----------+------------+
| ContactID | CategoryID |
+-----------+------------+
|         1 | Major      |
|         2 | Recruit    |
|         3 | General    |
|         4 | Recruit    |
+-----------+------------+

2 个答案:

答案 0 :(得分:1)

是的,有一个更简单的方法,在order by子句中使用top 1 with tiesrow_number

SELECT TOP 1 WITH TIES ContactID, CategoryID
FROM TableName
ORDER BY ROW_NUMBER() OVER(
    PARTITION BY ContactID 
    ORDER BY CASE CategoryID 
        WHEN 'General' THEN 1
        WHEN 'Major' THEN 2
        WHEN 'Recruit' THEN 3
        ELSE
    END
    )

但是,由于实际数据在层次结构中具有30个级别,因此您不想为每个数据手动编写一个when子句。
而是使用公用表表达式将层次结构的每个级别与数字配对,然后将表联接到此cte:

WITH CTESort AS
(
    SELECT Category, Sort
    FROM (VALUES
          ('General', 1), 
          ('Major', 2),
          ('Recruit', 3) 
          -- and so on...
     )V(Category, Sort)
)

SELECT TOP 1 WITH TIES ContactID, CategoryID
FROM TableName 
JOIN CTESort 
    ON TableName.CategoryID = CTESort.Category
ORDER BY ROW_NUMBER() OVER(PARTITION BY ContactID ORDER BY CTESort.Sort)

答案 1 :(得分:0)

参见下文:

select 'General' < 'Major';
 ?column? 
----------
 t
(1 row)

select 'Major' < 'Recruit';
 ?column? 
----------
 t
(1 row)

所以'General' < 'Major' < 'Recruit'是SQL的最简单方法:

select contractid,min(cateoryid) from level group by contractid order by contractid;
 contractid |   min   
------------+---------
          1 | Major
          2 | Recruit
          3 | General
(3 rows)