2015-09-20 1 views
1

У нас есть таблица «PROCESS» с первичным ключом process_id. Процессы имеют «элементы», которые хранятся в другой таблице «ПУНКТ» с (process_id, item_id) в качестве первичного ключа. Каждый элемент имеет «события», которые хранятся в еще одной таблице «СОБЫТИЕ» с (process_id, item_id, event_id) в качестве первичного ключа. Событие имеет тип (хранится в столбцах «события». «Event_type») Предположим, что есть события с типом «A».Выберите строки из таблицы, удовлетворяющие критериям для всех строк в дочерней таблице, которые имеют по меньшей мере одну запись в другой таблице.

Я хочу выбрать процессы, имеющие хотя бы одно событие типа «А» для всех своих элементов (так что, если у одного элемента нет такого события, мне не нужен такой процесс в наборе результатов).

я закончил с помощью следующего запроса:

SELECT needed_processes.process_id FROM (
SELECT items.process_id, items.number_of_items, events.number_of_events FROM 
(SELECT process.process_id, count(*) number_of_items FROM process 
    JOIN item ON process.process_id = item.process_id 
    GROUP BY process.process_id 
) items JOIN 
(SELECT needed_events.process_id, count(*) number_of_events FROM 
    (SELECT process.process_id, item.item_id FROM process JOIN item 
    ON process.process_id = item.process_id JOIN events ON item.process_id = event.process_id 
    AND item.item_id = event.item_id 
    WHERE event.event_type = 'A' 
    group by process.process_id, item.item_id 
) needed_events group by needed_events.process_id 
) events ON items.process_id = events.process_id 
where items.number_of_items = events.number_of_events) needed_processes 

Это подсчет количества элементов для процесса и проверяет, что количество требуемых событий для процесса равно это количество элементов.

Этот запрос трудно читать, трудно понять и не выглядит эффективным.

Есть ли более простые запросы (с точки зрения чтения или с точки зрения производительности) для этой задачи?

Я буду в порядке с запросами, специфичными для оракула, запросы агностики базы данных также приветствуются.

Примеры

процесса

|process_id| 
|1   | 
|2   | 
|3   | 
|4   | 

товара (пункт всегда принадлежит только одному процессу)

|process_id|item_id| 
|1   |11  | 
|1   |12  | 
|1   |13  | 
|2   |14  | 
|2   |15  | 
|3   |16  | 

Event (событие всегда принадлежат только к одному пункту)

|process_id|item_id|event_id|event_type| 
|1   |11  |21  |A   | 
|1   |11  |22  |A   | 
|1   |11  |23  |B   | 
|1   |13  |24  |A   | 
|2   |14  |25  |A   | 
|2   |14  |26  |A   | 
|2   |15  |27  |A   | 
|2   |15  |28  |B   | 

Результат

|process_id| 
|2   | 

process_id = 1 должен быть отфильтрован, так как он не имеет событие типа A для элемента 12. Он имеет два события типа A для элемента 11, но они должны рассматриваться как «элемент 11 имеет событие А». process_id = 2 должен возвращаться в результирующем наборе, поскольку он имеет события типа A для всех его элементов. Он имеет два события типа A для пункта 14, и это не должно влиять на результат. process_id = 3 не должен возвращаться, потому что он не имеет каких-либо событий (=> не имеет события типа A для каждого из его элементов) process_id = 4 не должен возвращаться, потому что у него нет никаких элементов (угол кейс).

+0

Выборочные данные и желаемые результаты помогут объяснить то, что вы пытаетесь сделать. –

ответ

1

Это возвращает все процессы, где есть событие «A» для каждый пункт:

select process_id 
from events 
group by process_id 
having count(distinct item_id)          -- all items 
    = count(distinct case when event_type = 'A' then item_id end) -- only items with event 'A' 
+0

Спасибо, это просто замечательно, можно легко понять и отлично работает! – frenzykryger