Select average from join MYSQL - mysql

I am trying to get an average on the last join:
INNER JOIN rating r
ON r.rid = (SELECT MAX(rid) FROM rating WHERE uid = u.uid ORDER BY rid DESC LIMIT 1)
I am having some problems getting it to give me a rating with 1 decimal like 4.3 in rating. How can i do this in a simple way?
SELECT p.uid, u.name, u.description, u.url, u.picurl, u.mapurl, p.pid, p.price, r.rid, r.rating FROM utested u
INNER JOIN price p
ON p.pid = (SELECT MAX(pid) FROM price WHERE uid = u.uid ORDER BY uid DESC LIMIT 1)
INNER JOIN rating r
ON r.rid = (SELECT MAX(rid) FROM rating WHERE uid = u.uid ORDER BY rid DESC LIMIT 1)
ORDER BY u.name;
I have created a sql fiddle so you can try out the queries.
http://sqlfiddle.com/#!2/93b771/1

Consider the following. How does this result differ from the desired result?
+-----+------------+-------------+----------+------------+--------------+-----+-------+-----+--------+
| uid | name | description | url | picurl | mapurl | pid | price | rid | rating |
+-----+------------+-------------+----------+------------+--------------+-----+-------+-----+--------+
| 5 | Havana Pub | | | | | 35 | 74 | 11 | 5 |
| 3 | Hos Naboen | | | | | 33 | 74 | 9 | 5 |
| 2 | Javel | Musikk | javel.no | pic.jave.. | map.javel.no | 38 | 88 | 8 | 5 |
| 1 | Kick | Yay | kick.no | http://p.. | map.kick.no | 31 | 74 | 15 | 1 |
| 6 | Leopold | | | | | 36 | 74 | 12 | 5 |
| 4 | Victoria | | | | | 37 | 75 | 10 | 5 |
+-----+------------+-------------+----------+------------+--------------+-----+-------+-----+--------+
OK. I'm going to take a wild stab in the dark here...
SELECT p.uid
, u.name
, u.description
, u.url
, u.picurl
, u.mapurl
, p.pid
, p.price
, AVG(r.rating) rating
FROM utested u
JOIN price p
ON p.uid = u.uid
JOIN ( SELECT uid, MAX(pid) latest_price FROM price GROUP BY uid ) px
ON px.uid = p.uid
AND px.latest_price = p.pid
JOIN rating r
ON r.uid = u.uid
GROUP
BY u.name;
+-----+------------+-------------+----------+--------------+--------------+-----+-------+--------+
| uid | name | description | url | picurl | mapurl | pid | price | rating |
+-----+------------+-------------+----------+--------------+--------------+-----+-------+--------+
| 5 | Havana Pub | | | | | 35 | 74 | 5.5000 |
| 3 | Hos Naboen | | | | | 33 | 74 | 4.0000 |
| 2 | Javel | Musikk | javel.no | pic.javel... | map.javel.no | 38 | 88 | 5.0000 |
| 1 | Kick | Yay | kick.no | http://pri.. | map.kick.no | 31 | 74 | 3.4000 |
| 6 | Leopold | | | | | 36 | 74 | 3.5000 |
| 4 | Victoria | | | | | 37 | 75 | 4.0000 |
+-----+------------+-------------+----------+--------------+--------------+-----+-------+--------+

Related

Unable to use single-valued column from subquery table join in HAVING clause with aggregate value

Related question upon which I based this question here
For relevant tables and columns (a lot more exist than the following), I have a customer table with cust_id and state columns and an account table with account_id, cust_id, and avail_balance columns.
Example customer table:
| cust_id | state |
|--------:|-------|
| 1 | MA |
| 2 | MA |
| 3 | MA |
| 4 | MA |
| 5 | NH |
| 6 | MA |
| 7 | MA |
| 8 | NH |
| 9 | MA |
| 10 | NH |
| 11 | MA |
| 12 | NH |
| 13 | MA |
Example account table:
| account_id | cust_id | avail_balance |
|-----------:|--------:|--------------:|
| 1 | 1 | 1057.75 |
| 2 | 1 | 500 |
| 3 | 1 | 3000 |
| 4 | 2 | 2258.02 |
| 5 | 2 | 200 |
| 7 | 3 | 1057.75 |
| 8 | 3 | 2212.5 |
| 10 | 4 | 534.12 |
| 11 | 4 | 767.77 |
| 12 | 4 | 5487.09 |
| 13 | 5 | 2237.97 |
| 14 | 6 | 122.37 |
| 15 | 6 | 10000 |
| 17 | 7 | 5000 |
| 18 | 8 | 3487.19 |
| 19 | 8 | 387.99 |
| 21 | 9 | 125.67 |
| 22 | 9 | 9345.55 |
| 23 | 9 | 1500 |
| 24 | 10 | 23575.12 |
| 25 | 10 | 0 |
| 27 | 11 | 9345.55 |
| 28 | 12 | 38552.05 |
| 29 | 13 | 50000 |
Here is the format of the query which I wish to execute.
SELECT a.cust_id, SUM(a.avail_balance) AS cust_tot_bal
FROM
account AS a
INNER JOIN customer c ON a.cust_id = c.cust_id
CROSS JOIN (SELECT MAX(cust_id) AS max_nh_cust_id, MAX(nh_cust_tot_bal) AS max_nh_cust_tot_bal
FROM
(SELECT a.cust_id, SUM(avail_balance) AS nh_cust_tot_bal
FROM
account AS a
INNER JOIN customer c ON a.cust_id = c.cust_id
WHERE
c.state = 'NH'
GROUP BY a.cust_id) AS nh_cust_tot_bal) AS max_nh_cust_tot_bal_t
WHERE c.state = 'MA'
AND a.cust_id > max_nh_cust_id
GROUP BY a.cust_id;
This fails since it is unable to detect max_nh_cust_tot_bal from the previous join.
Expected result for the above example data (the cust_tot_bal column is optional):
| cust_id | cust_tot_bal |
|--------:|-------------:|
| 13 | 50000 |
You can get the maximum cust_id and sum of the customers of state 'NH' with this query:
SELECT MAX(cust_id) max_nh_cust_id,
MAX(t.max_nh_avail_balance) max_nh_avail_balance
FROM (
SELECT a.cust_id, SUM(a.avail_balance) AS max_nh_avail_balance
FROM account a INNER JOIN customer c
ON a.cust_id = c.cust_id
WHERE c.state = 'NH'
GROUP BY a.cust_id
) t
and you can join it like this:
SELECT m.cust_id, m.cust_tot_bal
FROM (
SELECT a.cust_id, SUM(a.avail_balance) AS cust_tot_bal
FROM account a INNER JOIN customer c
ON a.cust_id = c.cust_id
WHERE c.state = 'MA'
GROUP BY a.cust_id
) m
INNER JOIN (
SELECT MAX(cust_id) max_nh_cust_id,
MAX(t.max_nh_avail_balance) max_nh_avail_balance
FROM (
SELECT a.cust_id, SUM(a.avail_balance) AS max_nh_avail_balance
FROM account a INNER JOIN customer c
ON a.cust_id = c.cust_id
WHERE c.state = 'NH'
GROUP BY a.cust_id
) t
) n ON m.cust_id > n.max_nh_cust_id AND m.cust_tot_bal > n.max_nh_avail_balance
See the demo.
Results
> cust_id | cust_tot_bal
> ------: | -----------:
> 13 | 50000

Inner Join for four tables is not working?

I have four tables mls_user, mls_category, mls_entry, and bonus_point.
Following are the tables:
mls_user
*--------------------------*
| id | store_id | name |
*--------------------------*
| 1 | 101 | Santosh |
| 2 | 101 | Aman |
| 3 | 102 | Ankit |
| 4 | 101 | Suman |
| 5 | 101 | Ramesh |
*--------------------------*
mls_category
*----------------------------------------*
| cat_no | store_id | cat_type | cat_val |
*----------------------------------------*
| 1 | 101 | running | 1 |
| 2 | 101 | cycling | 4 |
| 3 | 102 | running | 1 |
| 4 | 102 | swiming | 2 |
*----------------------------------------*
mls_entry
*----------------------------------------------------------*
| id | user_id | store_id | category | distance | status |
*----------------------------------------------------------*
| 1 | 1 | 101 | 1 | 5 | Approved |
| 2 | 1 | 101 | 1 | 10 | Approved |
| 3 | 1 | 101 | 2 | 50 | Approved |
| 4 | 1 | 101 | 1 | 10 | Approved |
| 5 | 2 | 101 | 1 | 5 | Approved |
*----------------------------------------------------------*
bonus_point
*---------------------------------------------------------*
| bns_id | user_id | store_id | bonus_points | bonus_type |
*---------------------------------------------------------*
| 1 | 1 | 101 | 100 | fixed |
| 2 | 2 | 101 | 25 | % |
*---------------------------------------------------------*
Now from these four tables, I want below output:
*--------------------------------------------------------------*
| name | points | bonus_points | bonus_type | Total_Points |
*--------------------------------------------------------------*
| Santosh | 25 | 100 | fixed | 125 |
| Aman | 5 | 25 | % | 30 |
| Suman | 0 | 0 | - | 0 |
| Ramesh | 0 | 0 | - | 0 |
| Ankit | 0 | 0 | - | 5 |
*--------------------------------------------------------------*
I am using the following query but this query only shows the value for Santosh and aman
SELECT u.id, u.name, COALESCE(t1.points, 0) AS points, b.bonus_points
FROM mls_user u
LEFT JOIN
(SELECT e.user_id, SUM(e.distance / c.cat_value) AS points
FROM mls_entry e
INNER JOIN mls_category c ON e.store_id = c.store_id AND e.category = c.cat_no
WHERE e.status='approved' AND e.store_id = '101'
GROUP BY e.user_id ) t1 ON u.id = t1.user_id
INNER JOIN bonus_points b ON b.user_id = u.id
WHERE u.store_id = '101'
ORDER by points DESC
So where I am doing wrong in my query, Please help me in this.
In your bonus_points table you have only two entry related to user 1 and 2 (Santosh and aman) if you use INNER JOIN then you obtain only these user
in this case you need left JOIN for bonus_points Too
SELECT u.id, u.name, COALESCE(t1.points, 0) AS points, ifnull(b.bonus_points,0) bonus_point
FROM mls_user u
LEFT JOIN (
SELECT e.user_id, SUM(e.distance / c.cat_value) AS points
FROM mls_entry e
INNER JOIN mls_category c ON e.store_id = c.store_id
AND e.category = c.cat_no
WHERE e.status='approved'
AND e.store_id = '101'
GROUP BY e.user_id
) t1 ON u.id = t1.user_id
LEFT JOIN bonus_points b ON b.user_id = u.id
WHERE u.store_id = '101'
ORDER by points DESC

Mysql select most recent with date desc for each artist

i have 3 tables:
PK: Primary Key
FK: Foreign Key
mp3s table:
+---------+--------------+----------------------+
| id (PK) | tarck_title | date |
+---------+--------------+----------------------+
| 100 | shakira | 2001-01-12 00:00:00 |
| 101 | metallica | 2002-01-12 00:00:00 |
| 102 | james blunt | 2003-01-12 00:00:00 |
| 103 | shakira | 2004-01-12 00:00:00 |
| 104 | anathema | 2005-01-12 00:00:00 |
| 105 | nelson | 2006-01-12 00:00:00 |
| 106 | shakira | 2007-01-12 00:00:00 |
| 107 | bb king | 2008-01-12 00:00:00 |
| 108 | metallica | 2009-01-12 00:00:00 |
| 109 | nelson | 2010-01-12 00:00:00 |
| 110 | shakira | 2011-01-12 00:00:00 |
| 111 | bb king | 2012-01-12 00:00:00 |
+---------+--------------+----------------------+
artists table:
+---------+----------------+
| id (PK) | artist_name |
+---------+----------------+
| 14 | shakira |
| 221 | metallica |
| 320 | james blunt |
| 328 | shakira |
| 1004 | anathema |
| 1140 | nelson |
| 1401 | bb king |
+---------+----------------+
and tags table: PK(mp3_id, artist_id)
+-------------+----------------+
| mp3_id (FK) | artist_id (FK) |
+-------------+----------------+
| 100 | 14 |
| 101 | 221 |
| 102 | 320 |
| 103 | 14 |
| 104 | 1004 |
| 105 | 1140 |
| 106 | 14 |
| 107 | 1401 |
| 108 | 221 |
| 109 | 1140 |
| 110 | 14 |
| 111 | 1401 |
+---------+--------------------+
now, i need good query for this resaults. i want select 3 latest track from (shakira & bb king) order by date track. like this:
+---------+--------------+----------------------+
| id (PK) | tarck_title | date |
+---------+--------------+----------------------+
| 110 | shakira | 2011-01-12 00:00:00 |
| 106 | shakira | 2007-01-12 00:00:00 |
| 103 | shakira | 2004-01-12 00:00:00 |
| 111 | bb king | 2012-01-12 00:00:00 |
| 107 | bb king | 2008-01-12 00:00:00 |
+---------+--------------+----------------------+
or select 3 latest track from (shakira & bb king & metallica) order by date track. like this:
+---------+--------------+----------------------+
| id (PK) | tarck_title | date |
+---------+--------------+----------------------+
| 110 | shakira | 2011-01-12 00:00:00 |
| 106 | shakira | 2007-01-12 00:00:00 |
| 103 | shakira | 2004-01-12 00:00:00 |
| 111 | bb king | 2012-01-12 00:00:00 |
| 107 | bb king | 2008-01-12 00:00:00 |
| 108 | metallica | 2009-01-12 00:00:00 |
| 101 | metallica | 2002-01-12 00:00:00 |
+---------+--------------+----------------------+
EDIT:
this query is working but sort date desc not working:
SELECT `id`, `tarck_title`, `date`
FROM `mp3s`
WHERE `id` IN (
SELECT x.`mp3_id`
FROM `tags` x
INNER JOIN `tags` y ON y.`artist_id` = x.`artist_id` AND y.`mp3_id` <= x.`mp3_id`
INNER JOIN `mp3s` z ON z.`id` = x.`mp3_id`
WHERE x.`artist_id` IN (SELECT `artist_id` FROM `tags` WHERE `mp3_id` = 103)
GROUP BY x.`mp3_id` HAVING COUNT(*) <= 3
ORDER BY z.`date` DESC, x.`artist_id` DESC, x.`mp3_id`)
If I found the question, the query would be like the following:
(SELECT m.* FROM (tags as t JOIN artists as a on t.artist_id = a.id) JOIN mp3s as m on m.id = t.mp3_id
WHERE a.artist_name = 'Shakira'
ORDER BY m.date DESC
LIMIT 3)
UNION
(SELECT m.* FROM (tags as t JOIN artists as a on t.artist_id = a.id) JOIN mp3s as m on m.id = t.mp3_id
WHERE a.artist_name = 'bb King'
ORDER BY m.date DESC
LIMIT 3);
Also, If you want a compressed format of the query, you can find it in this post.
In MySQL, you can do this with variables:
SELECT m.*
FROM (SELECT m.*,
(#rn := if(#a = a.id, #rn + 1,
if(#a := a.id, 1, 1)
)
) as rn
FROM tags t JOIN
artists a
ON t.artist_id = a.id JOIN
mp3s m
ON m.id = t.mp3_id CROSS JOIN
(SELECT #a := -1, #rn := 0) params
WHERE . . .
ORDER BY a.id, m.date DESC
) m
WHERE rn <= 3;
In the inner WHERE, you can specify whatever artists or other conditions that you like.

mysql joining and concatinating different tables

I try to write a little voting tool. I have 3 tables: users, locations and votes. votes has 2 foreign keys (user_id and location_id).
Users (example data):
+----+----------+
| id | username |
+----+----------+
| 5 | user1 |
| 7 | user2 |
| 11 | user3 |
| 4 | user4 |
| 12 | user5 |
+----+----------+
Locations:
+----+----------------+
| id | locationname |
+----+----------------+
| 1 | Pasta |
| 2 | Burger |
| 3 | Pizza |
| 4 | Chinese |
| 5 | Thai |
+----+----------------+
Votes:
+----+---------+-------------+------------+
| id | user_id | location_id | date |
+----+---------+-------------+------------+
| 30 | 5 | 1 | 2016-06-30 |
| 31 | 5 | 1 | 2016-07-01 |
| 32 | 7 | 1 | 2016-07-01 |
| 38 | 11 | 2 | 2016-07-01 |
| 39 | 4 | 1 | 2016-07-04 |
| 41 | 12 | 3 | 2016-07-04 |
| 44 | 5 | 4 | 2016-07-04 |
| 46 | 7 | 5 | 2016-07-04 |
+----+---------+-------------+------------+
The keypair date & user is unique so a user can't vote twice.
I now want to have a list like this for CURDATE():
+----------------+----------------+----------------------+
| locationname | Votes | Voters |
+----------------+----------------+----------------------+
| Pasta | 3 | user1, user2, user x |
| Burger | 2 | user3, user4 |
| Pizza | 1 | user5 |
| Chinese | 1 | user6 |
| Thai | 0 | |
+----------------+----------------+----------------------+
How can I solve this? Tried something like that:
SELECT locations.locationname AS location, count(*) AS count, GROUP_CONCAT(users.username SEPARATOR ', ') AS Voters
FROM votes
INNER JOIN locations ON votes.location_id=locations.id
WHERE date = CURDATE()
INNER JOIN users ON users.id=votes.user_id
WHERE location_id = "1" AND date = CURDATE()
GROUP BY location_id
ORDER BY count DESC;
Thanks
A friend of mine showed me how to solve this problem:
SELECT l.id AS locationid, l.locationname, count(username) AS count, GROUP_CONCAT(username SEPARATOR ", ") AS users
FROM locations l
LEFT JOIN votes v
ON v.location_id = l.id AND v.date = CURDATE()
LEFT JOIN users u
ON v.user_id = u.id
GROUP BY locationname
ORDER BY count DESC;

SQL Database - query to produce a list of doctor IDs and their names with the number of appointments they have?

I have three tables; doctor, person, and appointment.
doctor table:
+-----------+----------+---------+----------------+----------------+
| doctor_id | phone_no | room_no | date_qualified | date_appointed |
+-----------+----------+---------+----------------+----------------+
| 50 | 1234 | 1 | 1963-09-01 | 1991-05-10 |
| 51 | 1235 | 2 | 1973-09-12 | 1991-05-10 |
| 52 | 1236 | 3 | 1990-10-02 | 1993-04-01 |
| 53 | 1237 | 4 | 1965-06-30 | 1994-03-01 |
+-----------+----------+---------+----------------+----------------+
person table
+-----------+----------+-----------+---------------+------+
| person_id | initials | last_name | date_of_birth | sex |
+-----------+----------+-----------+---------------+------+
| 100 | T | Williams | 1972-01-12 | m |
| 101 | J | Garcia | 1981-03-18 | f |
| 102 | W | Fisher | 1950-10-22 | m |
| 103 | K | Waldon | 1942-06-01 | m |
| 104 | P | Timms | 1928-06-03 | m |
| 105 | A | Dryden | 1944-06-23 | m |
| 106 | F | Fogg | 1955-10-16 | f |
| 150 | T | Saj | 1994-06-17 | m |
| 50 | A | Cameron | 1937-04-04 | m |
| 51 | B | Finlay | 1948-12-01 | m |
| 52 | C | King | 1965-06-06 | f |
| 53 | D | Waldon | 1938-07-08 | f |
+-----------+----------+-----------+---------------+------+
appointment table
+-----------+------------+------------+-----------+---------------+
| doctor_id | patient_id | appt_date | appt_time | appt_duration |
+-----------+------------+------------+-----------+---------------+
| 50 | 100 | 1994-08-10 | 10:00:00 | 10 |
| 50 | 100 | 1994-08-16 | 10:50:00 | 10 |
| 50 | 102 | 1994-08-21 | 11:20:00 | 20 |
| 50 | 103 | 1994-08-10 | 10:10:00 | 10 |
| 50 | 104 | 1994-08-10 | 10:20:00 | 20 |
| 52 | 102 | 1994-08-10 | 10:00:00 | 10 |
| 52 | 105 | 1994-08-10 | 10:10:00 | 10 |
| 52 | 150 | 2014-03-10 | 12:00:00 | 15 |
| 53 | 106 | 1994-08-10 | 11:30:00 | 10 |
+-----------+------------+------------+-----------+---------------+
I need to create a query to produce a list of doctor IDs and their names with the number of appointments they have.
I have already created a statement to produce a list of doctor IDs with the number of appointments they have but im not sure how to produce a list with doctor IDs and their names.
The statement that I have now is:
select doctor.doctor_id, count(appointment.appt_time) as no_appt
from doctor
left join appointment
on doctor.doctor_id = appointment.doctor_id
group by doctor.doctor_id;
Please Help.
You need an additional join to the person table. Apparently, the doctor_id is the link. Yuck. This should be an explicit column rather than a re-use of the id.
select d.doctor_id, p.initials, p.last_name, count(appointment.appt_time) as no_appt
from doctor d left join
appointment a
on d.doctor_id = a.doctor_id left join
person p
on d.doctor_id = p.person_id
group by d.doctor_id, p.initials, p.last_name;
In MySQL, you don't actually need to add the two columns to the group by, but it is good practice to do so.
select doctor.doctor_id, person.initials, person.last_name, count(appointment.appt_time) as no_appt
from doctor
left join appointment on doctor.doctor_id = appointment.doctor_id
left join person on person.person_id = appointment.patient_id
group by doctor.doctor_id;
your SQL is nearly there - you just need to add a JOIN to the Person table to get the initial and last_name of the doctors - like this:
SELECT
d.doctor_id,
p.initials,
p.last_name,
COUNT(a.*)
FROM [person] p
JOIN [doctor] d ON p.person_id = d.doctor_id
LEFT JOIN [appointment] a ON a.doctor_id = d.doctor_id
GROUP BY d.doctor_id, p.initials, p.last_name
Hope this helps