Postgres LEFT JOIN не возвращает нули? - PullRequest
0 голосов
/ 24 января 2020

Не знаю, почему это происходит, но у меня есть такой запрос:

SELECT vote.user_id, ARRAY_AGG(COALESCE(vote.value, 0)) FROM item
LEFT JOIN vote ON item.item_id = vote.item_id
GROUP BY vote.user_id
ORDER BY user_id;

И таблица элементов содержит 100 элементов.

Я ищу результирующие строки, которые нужно сгруппировать на user_id и иметь каждый массив длиной 100 элементов. То есть, если значение не присутствует в таблице голосования, вместо этого вместо него вместо * в 1007 * вместо.

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

Я думал, что LEFT JOIN приведет к тому, что вместо пропущенных значений голосования будет поставлено NULL с, а для COALESCE чтобы превратить их в нули, но явно этого не происходит.

Ответы [ 2 ]

2 голосов
/ 24 января 2020

Ваша таблица предметов имеет 100 строк. Вы присоединяетесь к таблице голосов. Таким образом, вы получаете все голоса за элемент, например, 10 голосов за элемент 1, 5 голосов за элемент 2, 0 голосов за элемент 3, ... Если вы используете внутреннее соединение, вы потеряете 0 голосов за элемент 3, потому что нет проголосуйте за пункт 3 в таблице. Затем каждый голос связан с пользователем. Для элемента 3 нет голосования, поэтому, пока вы создаете результат для элемента 3 без голосов (NULL, который COALESCE превращается в 0), этот результат является пустым (т. Е. Идентификатор пользователя также, конечно, равен NULL). Это все, что делает внешнее объединение.

Затем вы группируете пользователей и собираете их голоса в массивы. Допустим, пользователь 1 имеет 40 голосов, пользователь 2 имеет 30 голосов, пользователь 3 не имеет голосов, а пользователь 4 имеет 20 голосов. Для этого вы получите три строки результатов (по одной для каждого пользователя в данных): одну для пользователя 1 с массивом из 40 голосов, одну для пользователя 2 с массивом из 30 голосов, одну для пользователя 4 с массивом из 20 голоса.

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

Для этого чтобы это произошло, вы должны сначала создать все нужные строки: пользователи х элементов. Затем выполните внешнее объединение голосов.

SELECT u.user_id, ARRAY_AGG(COALESCE(v.value, 0) ORDER BY i.item_id)
FROM users u
CROSS JOIN items i
LEFT JOIN votes v ON v.user_id = u.user_id and v.item_id = i.item_id
GROUP BY u.user_id
ORDER BY u.user_id;

Если вы хотите ограничить это для пользователей хотя бы одним голосом, то либо замените FROM users u на FROM (SELECT DISTINCT user_id FROM votes) u, либо добавьте HAVING COUNT(v.item_id) > 0.

0 голосов
/ 24 января 2020

Попробуйте:

select user_id, case when user_id  in (select user_id from vote) then ARRAY_AGG(value) 
else ARRAY_AGG(0) end as value from item group by user_id;

Вывод (2 и 3 отсутствуют в таблице голосования):

1  {101}
2  {0}
3  {0}
...