Выберите значение на основе пользовательской иерархии - PullRequest
0 голосов
/ 11 июня 2019

Я бы пытался выбрать значения на основе пользовательской иерархии.Эта иерархия не хранится в системе.

пример иерархии: Общие> Основные> Новобранец

Таблица уровней (не обязательно в порядке!)

+-----------+------------+
| 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 следует указать как Recruit.

+-----------+------------+
| 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 ]

1 голос
/ 11 июня 2019

Да, есть более простой способ, используя top 1 with ties и row_number в предложении order by:

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)
0 голосов
/ 11 июня 2019

См. Ниже:

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)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...