SQL Sum and Count JOIN Multiple tables - sql

Please help, I want to merge this two query
I have 3 Tables (places,ratings,places_image)
places
id
name
description
ratings
id
rating
place_id
user_id
places_image
id
place_id
image
These are the 2 queries:
SELECT places.*, SUM(rating) AS total_rating,COUNT(ratings.user_id) AS total_user FROM ratings, places WHERE ratings.place_id = places.id GROUP BY places.id
SELECT places.*, places_images.image FROM places, places_images WHERE places.id = places_images.place_id GROUP BY places.id
Query 1
Query 2
I tried to do this query but it give duplicate data for the aggregate function
SELECT places.id, places.name, places.description, places_images.image ,SUM(rating) AS total_rating,COUNT(ratings.user_id) AS total_user FROM places_images JOIN places ON places_images.place_id = places.id JOIN ratings ON ratings.place_id = places.id GROUP BY places.id
Query 3
How can i combine it ?

You need to use 2 Inner Join on the place_id and user_id
It'll be something like
SELECT SUM(r.rating) AS total_ratings, COUNT(r.user_id) AS total_users
FROM ratings r
INNER JOIN places p ON p.id = r.user_id
INNER JOIN places_image pi ON pi.place_id = r.place_id
GROUP BY r.id

Seems the only thing i need is to subquery it
select a.*, d.image, b.totalRating, c.totalUser from places a, ( select place_id, sum(rating) AS totalRating from ratings group by place_id ) b, ( select place_id, count(id) AS totalUser from ratings group by place_id ) c, places_images d where c.place_id = a.id and b.place_id = a.id and d.place_id = a.id GROUP BY a.id
Result
Thank you very much, GBU

Related

JOIN 2 tables ORDER BY SUM value

I have 2 tables: 1st is comment, 2nd is rating
SELECT * FROM comment_table a
INNER JOIN (SELECT comment_id, SUM(rating_value) AS total_rating FROM rating_table GROUP BY comment_id) b
ON a.comment_id = b.comment_id
ORDER BY b.total_rating DESC
I tried the above SQL but doesn't work!
Object is to display a list of comments order by rating points of each comments.
SELECT s.* FROM (
SELECT * FROM comment_table a
INNER JOIN (SELECT comment_id, SUM(rating_value) AS total_rating FROM rating_table GROUP BY comment_id) b
ON a.comment_id = b.comment_id
) AS s
ORDER BY s.total_rating DESC
Nest it inside an another select. It will then output the data in the correct order.

How to have SQL query with 2 subqueries divided

I have a database which has these tables:
Users (id, email)
Trips (id, driver_id)
MatchedTrips (id, trip_id)
I need to get for each user the total number of trips he created divided by the total matches found.
I am stuck in building the raw SQL query for this. Here is what I tried, and sure it's far from being correct.
SELECT
users.email,
total_trips.count1 / total_matches.count2
FROM users CROSS JOIN (SELECT
users.email,
count(trips.driver_id) AS count1
FROM trips
INNER JOIN users ON trips.driver_id = users.id
GROUP BY users.email) total_trips
CROSS JOIN (SELECT users.email, count(matches.trip_id) AS count2
FROM matches
LEFT JOIN trips ON matches.trip_id = trips.id
LEFT JOIN users ON trips.driver_id = users.id
GROUP BY users.email) total_matches;
You can calculate total trips and total matches for each driver in the way like this:
select driver_id, count(t.id) as total_trips, count(m.id) as total_matches
from trips t
left join matches m on (t.id = trip_id)
group by 1
Use this query as a derived table in join with users:
select email, total_trips, total_matches, total_trips::dec/ nullif(total_matches, 0) result
from users u
left join (
select driver_id, count(t.id) as total_trips, count(m.id) as total_matches
from trips t
left join matches m on (t.id = trip_id)
group by 1
) s on u.id = driver_id
order by 1;
SQLFiddle.
The simplest way is probably to use count(distinct):
select u.email,
count(distinct t.id) as num_trips,
count(distinct m.id) as num_matches,
(count(distinct t.id) / count(distinct m.id)) as ratio
from users u left join
trips t
on t.driver_id = u.id left join
matches m
on m.trip_id = t.trip_id
group by u.email;
Note: If emails are unique, then the query can be simplified. count(distinct) can be expensive under some circumstances.

Counting associations from multiple tables

I want to see how many association each of my records in a given table have. Some of these association have some conditions attached to them
So far I have
-- Count app associations
SELECT
distinct a.name,
COALESCE(v.count, 0) as visitors,
COALESCE(am.count, 0) AS auto_messages,
COALESCE(c.count, 0) AS conversations
FROM apps a
LEFT JOIN (SELECT app_id, count(*) AS count FROM visitors GROUP BY 1) v ON a.id = v.app_id
LEFT JOIN (SELECT app_id, count(*) AS count FROM auto_messages GROUP BY 1) am ON a.id = am.app_id
LEFT JOIN (
SELECT DISTINCT c.id, app_id, count(c) AS count
FROM conversations c LEFT JOIN messages m ON m.conversation_id = c.id
WHERE m.visitor_id IS NOT NULL
GROUP BY c.id) c ON a.id = c.app_id
WHERE a.test = false
ORDER BY visitors DESC;
I run into problem with the last join statement for conversations. I want to count the number of conversations that have at least 1 message where the visitor_id is not null. For some reason, I get multiple records for each app, ie. the conversations are not being grouped properly.
Any ideas?
My gut feeling, based on limited understanding of the big picture: in the nested query selecting from conversations,
remove DISTINCT
remove c.id from SELECT list
GROUP BY c.app_id instead of c.id
EDIT: try this
...
LEFT JOIN (
SELECT app_id, count(*) AS count
FROM conversations c1
WHERE
EXISTS (
SELECT *
FROM messages m
WHERE m.conversation_id = c1.id and
M.visitor_id IS NOT NULL
)
GROUP BY c1.app_id) c
ON a.id = c.app_id

Count and group the number of times each town is listed in the table

SELECT PEOPLE.TOWNKEY, TOWN_LOOKUP.TOWN FROM PEOPLE
INNER JOIN TOWN_LOOKUP
ON PEOPLE.TOWNKEY = TOWN_LOOKUP.PK
ORDER BY TOWN
Current Table Output:
You are missing the group by clause entirely:
SELECT tl.town, COUNT(*)
FROM people p
INNER JOIN town_lookup ON p.townkey = tl.pk
GROUP BY tl.town
ORDER BY tl.town

Writing a Mathematical Formula in SQL?

I have these tables: users, comments, ratings, and items
I would like to know if it is possible to write SQL query that basically does this:
user_id is in each table. I'd like a SQL query to count each occurrence in each table (except users of course). BUT, I want some tables to carry more weight than the others. Then I want to tally up a "score".
Here is an example:
user_id 5 occurs...
2 times in items;
5 times in comments;
11 times in ratings.
I want a formula/point system that totals something like this:
items 2 x 5 = 10;
comments 5 x 1 = 5;
ratings 11 x .5 = 5.5
TOTAL 21.5
This is what I have so far.....
SELECT u.users
COUNT(*) r.user_id
COUNT(*) c.user_id
COUNT(*) i.user_id
FROM users as u
JOIN COMMENTS as c
ON u.user_id = c_user_id
JOIN RATINGS as r
ON r.user_id = u.user_id
JOIN ITEMS as i
i.user_id = u.user_id
WHERE
????
GROUP BY u.user_id
ORDER by total DESC
I am not sure how to do the mathematical formula portion (if possible). Or how to tally up a total.
Final Code based on John Woo's Answer!
$sql = mysql_query("
SELECT u.username,
(a.totalCount * 5) +
(b.totalCount) +
(c.totalCount * .2) totalScore
FROM users u
LEFT JOIN
(
SELECT user_id, COUNT(user_id) totalCount
FROM items
GROUP BY user_id
) a ON a.user_id= u.user_id
LEFT JOIN
(
SELECT user_id, COUNT(user_id) totalCount
FROM comments
GROUP BY user_id
) b ON b.user_id= u.user_id
LEFT JOIN
(
SELECT user_id, COUNT(user_id) totalCount
FROM ratings
GROUP BY user_id
) c ON c.user_id = u.user_id
ORDER BY totalScore DESC LIMIT 10;");
Maybe this can help you,
SELECT u.user_ID,
(a.totalCount * 5) +
(b.totalCount) +
(c.totalCount * .2) totalScore
FROM users u LEFT JOIN
(
SELECT user_ID, COUNT(user_ID) totalCount
FROM items
GROUP BY user_ID
) a ON a.user_ID = u.user_ID
LEFT JOIN
(
SELECT user_ID, COUNT(user_ID) totalCount
FROM comments
GROUP BY user_ID
) b ON b.user_ID = u.user_ID
LEFT JOIN
(
SELECT user_ID, COUNT(user_ID) totalCount
FROM ratings
GROUP BY user_ID
) c ON c.user_ID = u.user_ID
ORDER BY totalScore DESC
but based on yur query above,thismay also work
SELECT u.users
(COUNT(*) * .5) +
COUNT(*) +
(COUNT(*) * 2) totalcore
FROM users as u
LEFT JOIN COMMENTS as c
ON u.user_id = c_user_id
LEFT JOIN RATINGS as r
ON r.user_id = u.user_id
LEFT JOIN ITEMS as i
ON i.user_id = u.user_id
GROUP BY u.user_id
ORDER by totalcore DESC
The only difference is by using LEFT JOIN. You will not use INNER JOIN in this situation because there are chances that user_id is not guaranteed to exists on every table.
Hope this makes sense
Here's an alternative approach:
SELECT
u.user_id,
SUM(s.weight) AS totalScore
FROM users u
LEFT JOIN (
SELECT user_id, 5.0 AS weight
FROM items
UNION ALL
SELECT user_id, 1.0
FROM comments
UNION ALL
SELECT user_id, 0.5
FROM ratings
) s
ON u.user_id = s.user_id
GROUP BY
u.user_id
I.e. for every occurrence of every user in every table, a row with a specific weight is produced. The UNIONed set of weights is then joined to the users table for subsequent grouping and aggregating.