2016-08-17 3 views
0

После установки:Рассчитать наиболее распространенное значение по всему полю 1 <-> 1..n | 0..N <-> 1 в один запрос

  • Сообщение 1..N < -> 1 Тема
  • Сообщение 0..N < -> 1 Настроение

Столы :

Message 
| id 
| text 
| mood_id 
| topic_id 

Topic 
| id 
| title 

Mood 
| id 
| title 

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

Я пытаюсь написать запрос, который выполняет следующие действия:

  • агрегировать количество сообщений для каждой темы
  • Найти наиболее часто используемое настроение для каждой темы

Оптимальных выходной будет список чего-то вроде этого:

| topic.id 
| topic.title 
| most_used_mood_id 
| message_count 

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

Ссылки на правильное направление приветствуются.

+0

Пожалуйста, отредактируйте ваш вопрос и предоставите образцы данных и результаты поиска. –

+0

@ GordonLinoff спасибо, я постараюсь дезинформировать некоторые данные и предоставить их здесь. – dvcrn

ответ

1

Получить желаемую агрегаты, запрашивающие только messages:

select 
    id, topic_id, mood_id, 
    count(topic_id) over (partition by topic_id) message_count, 
    count(mood_id) over (partition by topic_id, mood_id) mood_count 
from message; 

и использовать это в качестве производной таблицы:

select distinct on (topic_id) 
    t.id, 
    t.title, 
    mood_id as most_used_mood_id, 
    message_count 
from (
    select 
     id, topic_id, mood_id, 
     count(topic_id) over (partition by topic_id) message_count, 
     count(mood_id) over (partition by topic_id, mood_id) mood_count 
    from message 
    ) s 
join 
    topic t on t.id = topic_id 
order by 
    topic_id, mood_count desc; 
+0

Пройдя все решения и пробую разные вещи, я нашел, что это лучший рабочий. Какое влияние на производительность оказывает такой тип утверждения (с 'partition by' и' over')? Он масштабируется с большими таблицами? – dvcrn

+0

Обычно [функции окна] (https://www.postgresql.org/docs/9.5/static/tutorial-window.html) являются дорогостоящими. Простой 'count (...)' с 'group by ...' должен быть в 2-4 раза быстрее, чем 'count (...) over (partition ...)'.Однако функции окна допускают множественные агрегаты (по разным разделам) в одном простом запросе в случаях, когда * регулярные агрегаты * нуждаются в подзапросах и сложных объединениях. Простой тест на таблице с 1 миллионом строк показывает около 4 с для этого решения, а для запроса в другом ответе требуется 88 с. Из-за ошибок я не смог проверить третий запрос. – klin

1

Это предположение, основанное на вашем описании. Он объединяет сообщения, тему и настроения вместе, а затем агрегирует на уровне темы:

select distinct (t.topic_id) mtmo.* 
from (select t.topic_id, t.title, m.mood_id, count(*) as cnt 
     from message_topics m join 
      topic t 
      on mt.topic_id = t.topic_d join 
      message_moods mo 
      on mo.message_id = t.message_id and 
       mo.message_id = mt.message_id 
     group by t.topic_id, t.title 
    ) mtmo 
order by t.topic_id, cnt desc; 
+0

Я не думаю, что условие 't.mood_id = mo.mood_id' верное, нет смысла хранить' mood_id' в таблице 'topic', потому что у каждой темы может быть несколько настроений. – sagi

+0

@sagi. , , Хороший улов. Это должно быть 'message_id'. –

1

Поскольку вы хотите только mood_id, нет необходимости, чтобы выбрать из этой таблицы так:

SELECT tt.topic_id , tt.title, tt.mood_id, 
     (SELECT COUNT(*) FROM message mm WHERE mm.topic_id = tt.topic_id) as message_count 
FROM (
    SELECT s.topic_id,s.title,s.mood_id, 
      ROW_NUMBER() OVER(PARTITION BY s.topic_id,s.title ORDER BY s.cnt DESC) as rnk 
    FROM (
     SELECT t.topic_id,t.title,m.mood_id,count(*) as cnt 
     FROM topic t 
     INNER JOIN message m 
     ON(m.topic_id = t.id) 
     GROUP BY t.topic_id,t.title,m.mood_id) s) tt 
WHERE tt.rnk = 1 
Смежные вопросы