Предположим, у меня есть три таблицы: user
, group
и xref
, таблица, которая дает им RI "многие ко многим".
Возможно, я хочу посмотреть, к каким группам принадлежит каждый пользователь:
select
user.user_id,
user.user_name,
count(*) as group_count
from
user
inner join xref on user.user_id = xref.user_id
inner join group on group.group_id = xref.group_id
group by user.user_id, user.user_name
Пока все в порядке. Но что, если я хочу получить дополнительную информацию? Я пишу отчет и хочу узнать, является ли каждый пользователь разработчиком или менеджером контента. Теперь появляется анти-паттерн:
select
user.user_id,
user.user_name,
count(*) as group_count,
max( case group.group_name when 'Developers' then 'Y' else null end )
as is_dev
max( case group.group_name when 'Content Management' then 'Y' else null end )
as is_cm
from
user
inner join xref on user.user_id = xref.user_id
inner join group on group.group_id = xref.group_id
group by user.user_id, user.user_name
Это работает и дает ожидаемые результаты, но кажется, что это неправильно. Что я хочу спросить у Оракула, так это:
«Для каждого пользователя покажите мне, во сколько групп он входит. Кроме того, для всех имен групп на пользователя укажите, является ли« Разработчики »одним из значений».
Что я на самом деле спрашиваю так:
"Для каждого пользователя покажите мне, сколько групп в нем. Кроме того, для всех имен групп на пользователя покажите мне наибольшее значение, полученное этим выражением case
."
Причина того, что это анти-паттерн, заключается в том, что я в основном полагаюсь на тот факт, что Y
происходит , чтобы "всплыть" выше null
при оценке с помощью max()
. Если кто-то захочет скопировать или дополнить этот запрос, он может легко забыть об анти-паттерне и случайно изменить возвращаемые значения на то, что не использует такое же неинтуитивное совпадение.
По сути, я бы хотел написать следующий запрос:
select
user.user_id,
user.user_name,
count(*) as group_count,
any(group.group_name, 'Developers', 'Y', null) as is_dev,
any(group.group_name, 'Content Management', 'Y', null) as is_cm
from
user
inner join xref on user.user_id = xref.user_id
inner join group on group.group_id = xref.group_id
group by user.user_id, user.user_name
Я искал варианты, и кажется, что есть несколько потенциалов:
first_value
может работать, но я не могу понять, как ограничить соответствующее окно partition
правыми строками.
- Аналитические функции с предложением
over
могут работать, но я делаю хочу свернуть столбцы, по которым я группируюсь, так что это не совсем подходит.
- К сожалению, похоже, что
any
здесь задокументирована функция , но она существует только на таинственном диалекте, называемом Oracle OLAP DML, к которому я не могу получить доступ, используя только SQL на 10г. Но, кажется, он делает точно , что я хочу.
Это все, что я получил. Есть идеи?
Я понимаю, что есть две очень простые идеи: «Сделай это в коде» или «Сделай это в PL / SQL», но это обман. : -)