Mysql - Sum count result of join query - mysql

I have users, who can have many bookings during a time period. Each booking can have multiple people.
The query could look like:
SELECT users.*,
(SELECT COUNT(person) FROM person_to_booking WHERE person_to_booking.booking = bookings.id) AS people_per_booking
FROM users
LEFT JOIN bookings ON users.id = bookings.user
GROUP BY users.id
This returns one result, with the last bookings number of people. If I remove the GROUP BY then I get 4 rows, each with the correct number of people for that booking.
I need to have one row, with a SUM() of the COUNT(person). How can I achieve this?
EDIT
Tables are structured like so:
Users
id | name
---------
1 | Dave
2 | Bob
Bookings
id | user | company
-------------
1 | 1 | Big Group
2 | 1 | Big Group
3 | 2 | Small Company
Person to Bookings
id | person | bookings
----------------------
1 | 1 | 1
1 | 2 | 1
1 | 3 | 1
1 | 4 | 1
1 | 5 | 2
1 | 6 | 2
So a user can have bookings against them, and then a booking can have many persons.

IF I understand you correctly
SELECT users.*,
SELECT SUM(cper) FROM (SELECT COUNT(person) as cper FROM person_to_booking WHERE person_to_booking.booking = bookings.id) AS people_per_booking
FROM users
LEFT JOIN bookings ON users.id = bookings.user
GROUP BY users.id

Related

How can I not take in consideration values join without record on the db

I'm in front of a "minor" problem taht looks easy but I didn't suceed to resolve it.
I have three tables in my Database :
Table gp
____________
id | name |
____________
1 | Le Mans|
2 | Toulon |
3 | Rennes |
Table player
____________
id | name |
____________
1 | Thibaut|
2 | Fred |
3 | Samir |
Table Records
_____________________________
id | gp_id | player_id | time
_____________________________
1 | 1 | 1 | 17860
2 | 2 | 1 | 11311
3 | 3 | 1 | 33133
4 | 3 | 2 | 11113
5 | 2 | 2 | 44444
6 | 1 | 2 | 13131
7 | 1 | 3 | 11111
8 | 3 | 3 | 21112
I want to get a sum of time for players that have a record on every gp ( so in my case, just players Thibaut and Fred have a record on the 3 gp ( Samir has just a record on two gp ) ).
I have no idea how I can get that, of course this SQL query is retrieving a sum but from this query I want to escape the guys that don't have a record on every GPs, but I'm blocked at that point ...
SELECT p.name, sum(time)
from records r
join gp g on r.gp_id = g.id
join player p on r.player_id = p.id
group by r.player_id
Thanks in advance guys !
You could use having count to exclude the records that don't have a record on every GPs.
Try:
select p.name,
sum(`time`) as tot_sum
from records r
inner join player p on r.player_id=p.id
inner join gp g on g.id=r.gp_id
group by p.name
having count(distinct gp_id) = (select count(distinct id) from gp)
https://dbfiddle.uk/t8QwSFDY
having count(distinct gp_id) = (select count(distinct id) from gp) will match only the records in the record table that have a record on every gp.

How to count rows in nested tables with one SQL query?

I have three tables. Each User can have multiple Subscriptions and each Subscription can have multiple Payments.
Me goal is to count all Payments for a single User using one SQL query. Is it possible to do and how?
In the case below, The result for a User with id 1 should be 2 (because the User has two Payments)
Users
+----+------+
| Id | Name |
+----+------+
| 1 | John |
+----+------+
Subscriptions
+----+--------+-----------+
| Id | userId | data |
+----+--------+-----------+
| 1 | 1 | some data |
+----+--------+-----------+
| 2 | 1 | some data |
+----+--------+-----------+
Payments
+----+----------------+--------+
| Id | subscriptionId | amount |
+----+----------------+--------+
| 1 | 1 | 30 |
+----+----------------+--------+
| 2 | 2 | 50 |
+----+----------------+--------+
try like below by using join and aggregation
SELECT u.id, u.Name, COUNT(p.id) AS numberofpayment
FROM users u
Left JOIN Subscriptions s ON u.Id=s.userId
Left JOIN Payments p ON s.id=p.subscriptionId
GROUP BY u.id, u.Name
You can try to do something like this:
SELECT COUNT(p.Id) AS PaymentCount
FROM Users u
LEFT JOIN Subscriptions s ON u.Id=s.userId
LEFT JOIN Payments p ON s.id=p.subscriptionId
WHERE u.Id = #yourUserID
Pay attention on COUNT(p.Id) - it means count of existing payments.
PS: this answer for #Kickstart.

Finding many matches to one row in the same table and getting results from a second table based on the results

I know that the question title may not be quit clear to understand but I try to explain:
users_table:
id | name | admin | property_id
-----------------------------------
1 | x | 1 | 0
2 | y | 1 | 0
3 | z | 0 | 1
5 | t | 0 | 2
6 | u | 0 | 2
7 | o | 0 | 2
users_table has two or more records which are admin and some other records which belong to one of these admin records by matching the property_id with the id. In the end what I want is the admin row data and the count of its properties. This is what should be the output from the first part of the query:
id | name | admin | property_count
-----------------------------------
1 | x | 1 | 1
2 | y | 1 | 3
Until now I know how to get the desired results but here begins the problem.I have another table
sells_table:
id | seller_id | sell_amount
----------------------------
1 | 3 | 250
2 | 5 | 120
3 | 7 | 100
4 | 5 | 200
So this is the logic: every admin has many properties and each property has many sells.
I want all records for each admin from the users_table plus the count of its property_id.
And then query the sells_table in a way where for each property of each admin the number of sells and the sum of the total sells gets calculated.
for example this should be the result for the admin with the id 2 and the name y:
name | properties | property_sells | property_amount
--------------------------------------------------------
y | 3 | 3 | 420
y has 3 properties. Property with id 5 which belongs to y(admin) has two sells and id 7 which also belongs to y(admin) has one sell and the sum of these 3 sells is 420.
I think this is what you want:
select ua.id, ua.name, ua.admin, count(distinct u.id) as property_count,
sum(s.sell_amount) as amount
from users_table ua left join
users_table u
on ua.id = u.property_id left join
sales s
on s.seller_id = u.id
where ua.admin = 1
group by ua.id, ua.name, ua.admin;
http://sqlfiddle.com/#!9/36834d/2
SELECT u.id, U.name, u.admin, COUNT(DISTINCT ut.id) property_count, SUM(st.sell_amount)
FROM users_table u
LEFT JOIN users_table ut
ON u.id = ut.property_id
LEFT JOIN sells_table st
ON ut.id = st.seller_id
WHERE u.admin = 1
GROUP BY u.id, u.admin, u.name

SQL. Count rows where 2 columns foreigns is same type

I have such a task, and I can't solve it.
I have these tables:
users:
id | type
transactions:
id | sender_id | receiver_id
How can I make a select that will result this for each transactions row:
id | sender_id | receiver_id | sender_type | receiver_type
Tried JOIN but no success, I get only sender_id, receiver_id, type.
How can I get type column two times, for each one?
ex:
users:
id | type
1 | 4
2 | 3
3 | 1
4 | 3
transactions:
id | sender_id | receiver_id
1 | 2 | 3
2 | 1 | 4
3 | 3 | 1
result:
id | sender_id | receiver_id | sender_type | receiver_type
1 | 2 | 3 | 3 | 1
2 | 1 | 4 | 4 | 3
3 | 3 | 1 | 1 | 4
The trick you need for this is to JOIN the users table twice to the transactions table.
You'll need aliases to do this. I've used the one-letter aliases r and s. This is a very common application of the JOIN operation. It works as if there were two copies of the table.
It helps to create aliases for the column names too; some SQL clients work strangely when you feed them result sets with duplicate column names.
SELECT t.id, t.sender_id, t.receiver_id,
s.type sender_type,
r.type receiver_type
FROM transactions t
JOIN users s ON t.sender_id = s.id
JOIN users r ON t.receiver_id = r.id
ORDER BY t.id
You need to join to the users table explicitly for each type (sender and receiver), so for example:
SELECT
tr.id,
tr.sender_id,
tr.receiver_id,
us_sn.type,
us_rx.type
FROM
transactions tr
JOIN
users us_rx ON tr.receiver_id = us_rx.id
JOIN
users us_sn ON tr.sender_id = us_sn.id

Frequency join statement

I have 2 tables:
users:
id | name
-----------
1 | user 1
2 | user 2
3 | user 3
and posts:
id | userId | text
--------------------
1 | 1 | text 1
2 | 1 | text 2
3 | 2 | text 3
4 | 2 | text 4
5 | 2 | text 5
6 | 2 | text 6
I need to retrieve users ordered by post-frequency, e.g.:
id | name | posts
-------------------
2 | user 2 | 4
1 | user 1 | 1
3 | user 3 | 0
Some users might not have posts!
Currently I have 2 queries and doing it in 3 steps:
retrieve all users
retrieve all posts grouped by userId
use php to join the above
Question
Is the above possible to do in a single sql query?
select u.id, u.name, count(p.id) as posts
from users u
left join posts p on p.userid = u.id
group by u.id, u.name
order by posts desc
Another version, which prevents listing all fields from users table in group by clause. Also more fast in many cases IMO.
select u.id, u.name, coalesce(c.cnt, 0) as posts
from users u
left join
(select userId, couint(*) cnt from posts group by userId) c
on u.id = c.userId