SQL-запрос для поиска совпадений по нескольким критериям - PullRequest
3 голосов
/ 14 мая 2011

Если бы у меня была таблица PERMISSIONS, которая выглядела бы так:

PERSON         PERMISSION
------         ----------
Bob            red
John           red
John           blue
Mary           red
Mary           blue
Mary           yellow

и таблица THINGS, которая выглядела бы так:

THING          PERMISSION
-----          ----------
apple          red
eggplant       red
eggplant       blue

Я пытаюсь подойтис помощью чистого SQL-запроса, который позволил бы мне выяснить, какие PERSON s имеют доступ к каким THING s.По сути, я хочу запрос, который будет выглядеть примерно так:

SELECT person
  FROM ... vague handwaving here ...
 WHERE thing = 'eggplant'

, и он будет возвращать "Джон" и "Мэри".Ключевым моментом является количество разрешений, необходимых для доступа к объекту, является произвольным.

Мне кажется, это должно быть очевидно, но я просто не могу придумать элегантное решение.Предпочтительны совместимые решения Oracle.

Редактировать:

Решения от Косты и Дж.Брукса работают хорошо.Ниже приведена модифицированная версия решения Kosta, которое только дважды попадает в индексы, в отличие от 3x для Kosta и 4x для JBrooks (хотя я согласен с JBrooks в том, что это, вероятно, ненужная оптимизация).

SELECT p.person, num_permission, COUNT(p.person)
FROM permissions p
INNER JOIN (
    SELECT permission,
           COUNT(1) OVER (PARTITION BY thing) AS num_permission
      FROM things
     WHERE thing = 'eggplant'
  ) t ON t.permission = p.permission 
GROUP BY p.person, num_permission
HAVING COUNT(p.person) = num_permission

Ответы [ 4 ]

2 голосов
/ 14 мая 2011

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

Если я скажу эту проблему по-английски, то это:

  1. Выберите ЛЮДЕЙ, которые имеют разрешение на это.
  2. и не существует РАЗРЕШЕНИЯ требуется для этого, что ЧЕЛОВЕК не имеет.

Так что SQL будет:

SELECT DISTINCT P.PERSON, T.THING
FROM PERMISSIONS P
INNER JOIN THINGS T
ON P.PERMISSION = T.PERMISSION
WHERE NOT EXISTS
    (SELECT 1
    FROM THINGS TSUB
    WHERE TSUB.THING = T.THING
    AND TSUB.PERMISSION NOT IN
        (SELECT PSUB.PERMISSION
        FROM PERMISSIONS PSUB
        WHERE PSUB.PERSON = P.PERSON))
ORDER BY P.PERSON, T.THING

Сейчас я работаю в SQL Server, поэтому синтаксис может быть немного неправильным, но вы поняли.

Производительность. Кто-то скажет, что это не самый эффективный SQL, поэтому позвольте мне защитить себя сейчас. Таблицы разрешений и пользователей обычно находятся на меньшей стороне по сравнению с остальной частью системы, и сегодня в СУБД вам будет сложно загрузить достаточно данных в эти таблицы, чтобы этот оператор выполнялся дольше, чем одна десятая секунды, особенно после того, как индексы были в использовании. Так что в прошлом я был бы согласен с производительностью - сегодня я никогда не буду беспокоиться о производительности, если она не бросится на меня. Намного меньше обслуживания, когда вы подходите к нему таким образом.

1 голос
/ 14 мая 2011

Использование:

  SELECT p.person
    FROM PERMISSIONS p
    JOIN THINGS t ON t.permission = p.permission
   WHERE t.permission IN ('red', 'blue')
GROUP BY p.person
  HAVING COUNT(DISTINCT t.permission) = 2

Предложение WHERE обеспечивает включение только значений красного и синего. COUNT DISTINCT гарантирует, что дубликаты (два синих) не допускаются, так как это будет ложным срабатыванием.

1 голос
/ 14 мая 2011
select person
from permissions 
where permission in (select permission from things where thing='eggplant')
group by person
having count(person) = (select count(permission)  from things where thing='eggplant')
0 голосов
/ 14 мая 2011
select distinct person
from permissions p
join things      t on t.permission = p.permission
                  and t.thing      = 'eggplant'

должен это сделать.

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