2016-04-25 3 views
1

Я борюсь с этим конкретным запросом. Я делаю «таблицу лидеров» пользователей, которые добавили или получили большинство мест в своих руководствах.Подсчет с подзапросом, group_by и Left join

Моя модель данных выглядит следующим образом:

Users 

uuid  id 
string first_name 
bool  blogger 

Guests 

uuid  id 

Tips (join model) 

uuid  id 
uuid  guide_id 
uuid  place_id 
integer status 
uuid  owner_id 
string owner_type 

Guides 

uuid  id 
uuid  user_id 
string name 

Place 
uuid  id 
string name 

Пользователь может добавить места (корыто TIPS) к его/ее руководством. Этот же пользователь может также получать места (подсказки) от других пользователей к своему руководству. Эти советы могут быть приняты tips.status = 1.

То, что я хочу, это следующие:

first_name и количество всех мест были добавлены или принятые советы по всем их гидами, но не советы они дали другим пользователям, сгруппированных по users.blogger = 1.

пример:

Guest = true 

you  40 
user1  30 
user2  25 

Guest = false 
user3  20 
user4  15 
user5  5 

это то, что я до сих пор:

SELECT tips.owner_id, tips.owner_type, count(tips.owner_id) AS places_count 
FROM "tips" 
LEFT JOIN users on (owner_type ='User' AND users.id = owner_id) 
GROUP BY "tips"."owner_id", "tips"."owner_type" 
ORDER BY places_count DESC 
LIMIT 16 

Этот запрос делает возвращение счетчиков, но не принимает полученные советы в отношении и он также считает, данные советы на другой пользователи. У меня есть подозрение, что мне нужно использовать подзапросы, сначала выберите все идентификаторы руководства от данного пользователя, а во-вторых «просто» выберите количество всех советов, где guide_id = selected_guide_ids AND tips.status = 1. Наконец, сгруппируйте результаты по users.blogger = 1

Но как это написать?

Edit 1:.

Я обновил свой первоначальный вопрос с дополнительным Guest столом (именно поэтому я использую owner_type and owner_id instead из table_id И я обновил таблицу пользователей с блоггером (BOOL), на котором я хочу группировать результаты

образец данных:.

Users 

id  first_name  blogger 
user1 Daniel   true 
user2 Quassnoi  false 
user3 vkp    true 

Guests 

id 
guest_1 
guest_2 

Guides 

id   user_id  name 
guide_1  user_1  Bugers 
guide_2  user_1  Cool places 
guide_3  user_2  Amsterdam 

Tips 

id  guide_id place_id status owner_id owner_type 
tip1 guide_1  place_1  1  user_1  User  # user_1 added place_1 to his own guide guide_1 (accepted) 
tip2 guide_1  place_2  1  guest_1  Guest  # guest_1 suggested place_2 to user_1's guide guide_1 (accepted) 
tip2 guide_1  place_2  0  guest_1  Guest  # guest_1 suggested place_2 to user_1's guide guide_1 (rejected) 
tip_3 guide_2  place_1  1  user_2  User  # user_2 added place_1 to his own guide guide_3 (accepted) 
tip_4 guide_2  place_2  1  user_2  User  # user_2 added place_2 to his own guide guide_3 (accepted) 
tip_5 guide_2  place_3  1  user_1  User  # user_1 added place_3 to user_2's guide guide_2 (accepted) 

Places 

id  name 
place1 burgerbar 
place2 burgermeester 
place_3 bbq shack 

Что мой желаемый результат:

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

first_name tips_count blogger 

Quassnoi 3   false (2 added by himself, 1 received from user_1) 
Daniel  2   true (1 added by himself, 1 received from guest1. Note that the rejected tip does not count) 
vkp   0   false 

Edit 2

Я изменил ответ Quassnoi в немного к этому:

SELECT * 
FROM users u 
LEFT JOIN 
    (
    SELECT g.user_id, COUNT(*) tips_count 
    FROM guides g 
    JOIN tips t 
    ON  t.guide_id = g.id 
    AND (t.owner_id = g.user_id AND t.status = 1) 
    GROUP BY g.user_id 
    ) g 
ON  g.user_id = u.id 
ORDER BY tips_count DESC 

Это, однако, возвращает все записи, в которых tips_count является NULL первым. Я хочу, чтобы они были 0 вместо NULL. Как я могу наложить NULL tips_count на 0?

Edit 3:

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

SELECT * 
FROM users u 
LEFT JOIN 
    (
     SELECT g.user_id, COUNT(*) tips_count 
     FROM guides g 
     JOIN tips t 
     ON  t.guide_id = g.id 
     AND  (t.guide_id = g.id AND t.status = 1) 
     GROUP BY g.user_id 
    ) g 
ON g.user_id = u.id 
ORDER BY tips_count DESC 
+1

Данные примера и ожидаемый результат помогут ответить на вопрос. –

+1

Я читал ваш вопрос 3 раза, и я ничего не могу сделать, не просматривая данные. –

+1

Как вы можете сказать, что руководство принадлежит пользователю? – Quassnoi

ответ

1

Кажется, что это на самом деле не имеет значения, кто добавил/предложил место. Как только он будет принят (статус 1), он принадлежит руководству и, следовательно, пользователю гида. Следовательно:

select u.first_name, u.blogger, count(t.id) 
from users u 
left join guides g on g.user_id = u.id 
left join tips t on t.guide_id = g.id and t.status = 1 
group by u.id 
order by count(t.id) desc; 
+0

Вы правы! Это работает как шарм (статус неоднозначен, поэтому я добавил 't.status = 1'). Благодаря!! –

+0

А, да, я просто забыл квалификатор статуса. Рад, что это работает для вас. –

1

Способ, которым настроена ваша схема сейчас, невозможно определить, какой проводник принадлежит пользователю.

Предполагая, что есть guide.owner вы забыли упомянуть (или забыл добавить), было бы:

SELECT * 
FROM user u 
LEFT JOIN 
     (
     SELECT g.owner, COUNT(*) cnt 
       guide g 
     JOIN tips t 
     ON  t.guide_id = g.id 
       AND (t.owner_id = g.owner OR t.status = 1) 
     GROUP BY 
       g.owner 
     ) g 
ON  g.owner = u.id 
+0

Я действительно забыл добавить user_id в руководства. Спасибо за ваш ответ, я собираюсь проверить его сразу же! Я добавлю некоторые данные теста и данные результата к моему вопросу. –

+0

От может быть полезно здесь – Strawberry

+0

Я действительно получаю синтаксическую ошибку. Я немного изменил ваш ответ и добавил «SORT BY tips_count DESC», однако это возвращает много NULL tips_count, где я хочу, чтобы 'tips_count' был 0 вместо NULL Я обновил свой вопрос соответствующим образом. –

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