2016-08-02 4 views
1

У меня есть две таблицы (события и события). Каждое событие имеет 0 или более записей в таблице вхождения. Я хочу суммировать количество вхождений и получить первые 5 результатов. У меня есть SQL, который работает для этого, пока все события имеют записи в таблице вхождения. Где есть событие, в котором нет записей в таблице вхождениях, которая заканчивается вверху списка.Как выбрать 3 самых больших результата, но исключить нулевые значения

Какой правильный SQL для этого?

Определения Таблица

Событие
ID - целочисленные
EventName - VARCHAR (200)

Появления
ID - INT
event_id - INT
Отметка - DateTime
TimesOccurred - int

Для события с ID 1 (название события - 'переключение контекста'), я мог бы иметь соответствующие строки в таблице вхождений:

ID: 1, event_id: 1, Отметка: «2016- 08-02 5:52:00' , TimesOccurred: 50
ID: 8, event_id: 1, Отметка: '2016-08-02 7:11:00', TimesOccurred: 20

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

Следующий SQL даст мне первые 5 событий, суммируя столбцы TimesOccurred для всех событий с тем же идентификатором.

SELECT Events.Name, t.total as Total FROM Events 
LEFT JOIN 
(SELECT Occurrences.Event_ID, sum(Events.TimesOccurred) as total FROM Occurrences 
INNER JOIN Events on Events.id = Occurrents.Event_ID GROUP BY Events.id) t 
on Events.id = t.Event_ID ORDER BY t.total DESC limit 5; 

Это может дать мне

Segfault 20
контекстного переключатель 10

Однако, если у меня есть событие с именем ООЙ с идентификатором 3, и нет записей в таблице «Поступления» с идентификатором Event_ID 3 я получаю следующее:

ООМ
Segfault 20
контекстного переключатель 10

Я попытался изменить мой запрос:

SELECT Events.Name, COALESCE(t.total, 0) as Total FROM Events 
LEFT JOIN 
(SELECT Occurrences.Event_ID, sum(Events.TimesOccurred) as total FROM Occurrences 
INNER JOIN Events on Events.id = Occurrents.Event_ID GROUP BY Events.id) t 
on Events.id = t.Event_ID ORDER BY t.total DESC limit 5; 

Это возвращает

ООМ 0
Segfault 20
переключения контекста 10

Я считаю, что это потому, что я заказываю t.total, и COALESC не устанавливает t.total 0, где результат равен null, а вместо этого возвращает 0, где результат равен нулю.

Любая идея, как я могу исключить нулевые значения из моих 5-ти ведущих событий?

Спасибо,

+1

'sum (Events.TimesOccured)' ????? TimesOccurred в таблице «Загрузки»? – jonju

ответ

3

В Postgres можно определить обработку нулевых значений в ORDER BY пункта путем добавления NULLS [LAST/FIRST] после направления сортировки.

Кроме того, вам нужно только один раз посетить обе таблицы - дополнительная производная таблица не требуется.

SELECT Events.Name, sum(Occurences.TimesOccurred) as Total 
FROM Events 
LEFT JOIN Occurrences ON Events.id = Occurrences.Event_ID 
GROUP BY 1 
ORDER BY 2 DESC NULLS LAST 
LIMIT 5 

От manual (смелы курсива - причина вы получали аннулируют в ваших верхних 5 запросов):

По умолчанию, нулевые значения вроде как если больше, чем любое ненулевого значения ; , то есть NULLS FIRST по умолчанию для DESC-заказа и NULLS LAST в противном случае.

Если вам все еще нужно возвращать 0, когда нет occurencies (потому что вы можете иметь 5 или меньше событий в общей сложности), то добавление COALESCE() является путь - который вы сделали, кстати.


Я также добавил целые псевдонимы столбцов в GROUP BY и ORDER BY положений.

Вы также можете сделать псевдонимы для имен таблиц, чтобы немного сократить код.

1

Я хотел бы предложить вам упростить запрос и использовать NULLS LAST:

SELECT e.Name, sum(o.TimesOccurred) as total 
    FROM Events e LEFT JOIN 
     Occurrences o I 
     ON Events.id = o.Event_ID 
    GROUP BY e.Name 
    ORDER BY total DESC NULLS LAST 
    LIMIT 5; 

Обратите внимание, что только один соединение между двумя таблицами необходимо.

Смежные вопросы