Проблема SQL-запроса в PostgreSQL - PullRequest
0 голосов
/ 06 мая 2018

У меня есть три таблицы для пользователей и права доступа пользователей, как показано ниже:

create table users (id int, login varchar, organization varchar);
create table groups (id int, name varchar);
create table user_groups (gid int, uid int,
constraint fk_users_groups foreign key(gid) references groups(id),
constraint fk_users_users foreign key(uid) references users(id)
);

Позволяет вставить несколько записей:

insert into groups values(1, 'Data Entry'), (2, 'Sender'), (3, 'Receiver'), 
(4, 'Reviewer'), (5, 'Checker'), (6, 'Approver'), (7, 'Nothing'), (8, 
'Everything'), (9, 'HR Systems'), (10, 'Check System'), (11, 'Final');
insert into users (1, 'Ahmad'), (2, 'Sam'), (3, 'John'), (4, 'Smith'), 
(5, 'Roy');
insert into user_groups values (1, 1), (2, 1), (3, 1), (8, 1), (9, 1), (4, 2), 
(5, 2), (10, 2), (11, 2), (6, 3), (7, 4);  

Теперь я хочу получить идентификатор пользователя, логин и тип пользователя как таковой, если пользователь, имеющий («ввод данных», «отправитель», «получатель») группы, должен вывести «HR» (нам все равно для других групп, если он есть или нет, например: здесь у него есть и другие группы, а не те, которые нам нужны для типа пользователя «HR») для него как типа пользователя, если он / она входит в («рецензент», «проверка» "), затем следует печатать" Check ", иначе для любых других групп следует печатать" Any ".

Желаемый вывод:

User ID      Login       UserType  
   1         Ahmad         HR  
   2         Sam           Check  
   3         John          Any  
   4         Smith         Any

Ответы [ 4 ]

0 голосов
/ 06 мая 2018

В Postgres, DISTINCT ON может быть самым простым подходом:

SELECT DISTINCT ON (u.id) u.id AS user_id, u.login, g.userType
FROM users u JOIN
     user_groups ug
     ON u.id = ug.uid JOIN
     (SELECT g.*,
             (CASE WHEN g.name IN ('Data Entry', 'Sender', 'Receiver') THEN 'HR'
                   WHEN g.name IN ('Reviewer', 'Checker') THEN 'Check'
                   ELSE 'Any' 
              END) AS userType,
             (CASE WHEN g.name IN ('Data Entry', 'Sender', 'Receiver') THEN 1
                   WHEN g.name IN ('Reviewer', 'Checker') THEN 2
                   ELSE 3
              END) AS userType_priority
      FROM groups g
     ) g
     ON ug.gid = g.id
ORDER BY u.id, g.userType_priority;

Другая альтернатива - CASE EXISTS:

select u.*,
       (case when exists (select 1
                          from user_groups u join
                               groups g
                               on ug.gid = g.id
                          where g.name in ('Data Entry', 'Sender', 'Receiver')
                         )
             then 'HR'
             when exists (select 1
                          from user_groups u join
                               groups g
                               on ug.gid = g.id
                          where g.name in ('Reviewer', 'Checker')
                         )
             then 'Check'
             else 'Any'
        end) as UserType
from users u;

Несмотря на сложный внешний вид запроса, он не требует агрегирования или сортировки, поэтому он может иметь лучшую производительность.

Я бы порекомендовал включить UserType в таблицу groups. Это значительно упростит запрос и сделает любые приложения, использующие UserType, более согласованными.

0 голосов
/ 06 мая 2018

Вы можете использовать:

SELECT DISTINCT u.id AS user_id, u.login,
       CASE WHEN g.name IN ('Data Entry', 'Sender', 'Receiver') THEN 'HR'
            WHEN g.name IN ('Reviewer', 'Checker') THEN 'Check'
            ELSE 'Any' 
       END AS userType
FROM users u
JOIN user_groups ug ON u.id = ug.uid
JOIN groups g ON ug.gid= g.id
ORDER BY u.id;

Демоверсия DBFiddle

0 голосов
/ 06 мая 2018

Добавьте к группам таблиц столбец, содержащий то, что должно быть напечатано, когда в следующий раз вам понадобится добавить новое значение в группы, вы будете рады, что сделали это.

изменить группы таблиц добавить текст столбца usertype; обновить группы set usertype = 'HR', где id от 1 до 3; обновить группы set usertype = 'Check', где id от 4 до 5;

SELECT DISTINCT u.id AS user_id, u.login,
  COALESCE(g.usertype,'any')
FROM users u
JOIN user_groups ug ON u.id = ug.uid
LEFT OUTER JOIN groups g ON ug.gid= g.id and g.userype is not null
ORDER BY u.id;

это напечатает две строки для любого пользователя, у которого есть HR и Check, и одну строку для всех остальных.

0 голосов
/ 06 мая 2018

Вы можете использовать max(case(, чтобы найти верхнюю группу, в которой кто-то находится. Здесь я определил порядок, добавив префикс usertype с 1, 2 или 3:

select  u.id
,       login
,       substring(max(case
            when name in ('Data Entry', 'Sender', 'Receiver') THEN '3 HR'
            when name in ('Reviewer', 'Checker') THEN '2 Check'
            else '3 Any'
            end) from 3)
from    users u
left join
        user_groups ug
on      ug.uid = u.id
left join
        groups g
on      g.id = ug.gid
group by
        u.id
,       login

Пример на DBFiddle.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...