Рассчитать на GROUP BY, а также на общее количество результатов - PullRequest
0 голосов
/ 26 декабря 2018

У меня есть три таблицы:

users, которые имеют только два столбца: id: INT, name: TEXT

houses, которые имеют три столбца: id: INT, user_id: INT, sold_at: DATE

users_with_house_permissions, который имеет два столбца: id: INT, user_id: INT

У меня есть этот запрос, который определяет количество домов, проданных пользователем (при условии, что у него есть house_permissions):

SELECT users.id as user_id, COUNT(*) as houses_sold
FROM users
JOIN users_with_house_permissions hp ON hp.user_id = users.id
LEFT JOIN houses on houses.user_id = users.id AND houses.sold_at IS NOT NULL
GROUP BY users.id

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

Так, например, если у меня есть следующее содержимое:

users (id, name):

1, John
2, Carla
3, Bula

users_with_house_permissions (id, user_id):

1, 1
2, 2

houses (id, user_id, sold_at):

1, 1, '2018-10-10'

Я быкак результат запроса:

user_id: 1
houses_sold: 1
total_count: 2

user_id: 2
houses_sold: 0
total_count: 2

Итак, total_count будет представлять количество строк, которые этот запрос возвратит.

Ответы [ 3 ]

0 голосов
/ 26 декабря 2018

Вы можете использовать количество аналитических / оконных функций без каких-либо разделов:

SELECT users.id as user_id, COUNT(*) as houses_sold,

  COUNT(*) OVER() as total_count -- count of rows returned by query

FROM users
JOIN users_with_house_permissions hp ON hp.user_id = users.id
LEFT JOIN houses on houses.user_id = users.id AND houses.sold_at IS NOT NULL
GROUP BY users.id

Работает как любая другая аналитическая функция;он рассчитывает на раздел, но если не указан раздел, то он учитывается на весь набор данных.В этом случае подсчет выполняется после группировки, поэтому count(*) подсчитывает количество элементов в группе, count(*) over() подсчитывает количество групп в наборе данных

Кто-то еще отправил sum(count(*)) over(), который является эффективным эквивалентом подсчета строк до их группировки.Если у вас был набор данных «кто продал дом», и он получился таким:

john
john
john
mary

4 дома были проданы, Джон продан 3, Мэри продана 1. В агентстве работают 2 торговых представителя..

COUNT(*) FROM ... GROUP BY name дает «Джон продал 3, Мэри продал 1» и приводит к набору данных:

john, 3
mary, 1

Если бы мы подсчитали это количество, у нас было бы 4т.е. 3 + 1.Это фактически количество домов до того, как группировка была сделана.SUM(COUNT(*)) OVER() отсюда количество строк, которые у нас были до того, как мы создали группу.Важно иметь в виду, что COUNT (*) принадлежит GROUP BY и станет целым числом, которое впоследствии будет СУММЕРЕНО СУММОЙ.Вероятно, было бы легче увидеть, если бы мы использовали подзапрос:

SELECT name, the_count, SUM(the_count) OVER()
FROM (SELECT name, count(*) as the_count FROM sales GROUP BY name) subquery

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

SELECT name, count(*), sum(count(*)) over() FROM sales GROUP BY name

Таким образом, мы дойдем до того момента, когда вы оцените, что аналитика применяется после выполнения группировки, это означает, что где COUNT(*) OVER()счетчик количества строк в наборе данных после завершения операции группировки.Группировка произвела john,3|mary,1, поэтому COUNT (*) OVER () это производит 2 - количество строк в наборе данных

Документация, если вы хотите прочитать больше, называется «Функции Windows» и может бытьнашел где-то как здесь: https://www.postgresql.org/docs/9.1/tutorial-window.html

Это для PG 9.1;не забудьте изменить вид на конкретную версию PG

0 голосов
/ 26 декабря 2018

Я полагаю, что вы хотите:

select uhp.user_id, count(h.id) as houses_sold,
       sum(count(h.id)) over () as total_count
from users_with_house_permissions left join
     houses h
     on h.user_id = uhp.user_id
group by uhp.user_id;

Похоже, вам не нужна таблица users, потому что вы хотите, чтобы пользователи только в users_with_house_permissions.

count()подсчитывает количество совпадающих строк, поэтому вы можете получить строки с количеством 0.Затем оконная функция получает сумму по всем строкам.

0 голосов
/ 26 декабря 2018

Вы можете попробовать ниже - скалярный подзапрос

SELECT users.id as user_id, COUNT(*) as houses_sold,(select count(*) from users_with_house_permissions a) as totalcount
FROM users
JOIN users_with_house_permissions hp ON hp.user_id = users.id
LEFT JOIN houses on houses.user_id = users.id AND houses.sold_at IS NOT NULL
GROUP BY users.id
...