Mysql select most recent with date desc for each artist - mysql

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.

Related

Write a query in SQL to display the details of the current job for those employees who worked as a Sales Representative in the past

Table -
job_history
+-------------+------------+------------+------------+---------------+
| EMPLOYEE_ID | START_DATE | END_DATE | JOB_ID | DEPARTMENT_ID |
+-------------+------------+------------+------------+---------------+
| 102 | 2001-01-13 | 2006-07-24 | IT_PROG | 60 |
| 101 | 1997-09-21 | 2001-10-27 | AC_ACCOUNT | 110 |
| 101 | 2001-10-28 | 2005-03-15 | AC_MGR | 110 |
| 201 | 2004-02-17 | 2007-12-19 | MK_REP | 20 |
| 114 | 2006-03-24 | 2007-12-31 | ST_CLERK | 50 |
| 122 | 2007-01-01 | 2007-12-31 | ST_CLERK | 50 |
| 200 | 1995-09-17 | 2001-06-17 | AD_ASST | 90 |
| 176 | 2006-03-24 | 2006-12-31 | SA_REP | 80 |
| 176 | 2007-01-01 | 2007-12-31 | SA_MAN | 80 |
| 200 | 2002-07-01 | 2006-12-31 | AC_ACCOUNT | 90 |
+-------------+------------+------------+------------+---------------+
You can use the following using a sub-select to get the current / last job and EXISTS to check if the employee worked as a sales representative in the past:
SELECT jh.*
FROM job_history jh INNER JOIN (
SELECT EMPLOYEE_ID, MAX(START_DATE) AS START_DATE
FROM job_history
GROUP BY EMPLOYEE_ID
) cj ON jh.EMPLOYEE_ID = cj.EMPLOYEE_ID AND jh.START_DATE = cj.START_DATE
WHERE EXISTS (
SELECT 1
FROM job_history
WHERE EMPLOYEE_ID = jh.EMPLOYEE_ID AND JOB_ID = 'SA_REP' AND START_DATE < jh.START_DATE
)
demo on dbfiddle.uk

Self-Join to get First Record and Record on Last day of Month

I have a table that looks like this. The table is generated by pinging each account in the system everyday to record an 'mrr' amount. The 'mrr' account is 0 if the account is not paying. It records a value when the account starts paying. If the account cancels, the mrr recorded goes back to 0.
+-----------+------------+------------+-----+
| paylog_id | account_id | date | mrr |
+-----------+------------+------------+-----+
| 1001 | 99 | 2016-01-15 | 0 |
| 1002 | 99 | 2016-01-16 | 0 |
| 1003 | 99 | 2016-01-17 | 0 |
| 1004 | 99 | 2016-01-18 | 0 |
| 1005 | 99 | 2016-01-19 | 0 |
| 1006 | 99 | 2016-01-20 | 25 |
| 1007 | 99 | 2016-01-21 | 25 |
| 1008 | 99 | 2016-01-22 | 25 |
| 1009 | 99 | 2016-01-23 | 25 |
| 1010 | 99 | 2016-01-24 | 25 |
| 1011 | 99 | 2016-01-25 | 25 |
| 1012 | 99 | 2016-01-26 | 25 |
| 1013 | 99 | 2016-01-27 | 25 |
| 1014 | 99 | 2016-01-28 | 0 |
| 1015 | 99 | 2016-01-29 | 0 |
| 1016 | 99 | 2016-01-30 | 0 |
| 1017 | 99 | 2016-01-31 | 0 |
| 1018 | 99 | 2016-02-01 | 0 |
| 1019 | 79 | 2016-02-23 | 255 |
| 1020 | 79 | 2016-02-24 | 255 |
| 1021 | 79 | 2016-02-25 | 255 |
| 1022 | 79 | 2016-02-26 | 255 |
| 1023 | 79 | 2016-02-27 | 255 |
| 1024 | 79 | 2016-02-28 | 50 |
| 1025 | 79 | 2016-02-29 | 25 |
| 1026 | 79 | 2016-03-01 | 25 |
| 1027 | 79 | 2016-03-02 | 27 |
+-----------+------------+------------+-----+
I need to know 2 pieces of information-
What is the amount on the very first date the account starts paying?
What is the amount on the last day of the month of the month in which the account started paying?
The result in the above example should be:
+-----------+------------+------------+-----+------------+-------------+------------+------+
| paylog_id | account_id | date | mrr | paylog_id1 | account_id1 | date1 | mrr1 |
+-----------+------------+------------+-----+------------+-------------+------------+------+
| 1006 | 99 | 2016-01-20 | 25 | 1017 | 99 | 2016-01-31 | 0 |
| 1018 | 79 | 2016-02-23 | 255 | 1024 | 79 | 2016-02-29 | 25 |
+-----------+------------+------------+-----+------------+-------------+------------+------+
I know I can get the first payment date using this query:
SELECT
a.paylog_id,
a.account_id,
a.date,
a.mrr
FROM
ds_paylogs a
INNER JOIN (
SELECT
account_id,
min(date) mdate, mrr
FROM
ds_paylogs b
where b.mrr >0
GROUP BY
account_id
) b ON a.account_id = b.account_id
AND a.date = b.mdate
Result:
+------+----+----------+-----+
| 1006 | 99 | 20-01-16 | 25 |
+------+----+----------+-----+
| 1018 | 79 | 23-02-16 | 255 |
+------+----+----------+-----+
Separately, I can get the last day of the month on the first payment date using:
SELECT
a.paylog_id,
a.account_id,
a.date,
a.mrr
FROM
ds_paylogs a
INNER JOIN (
SELECT
account_id,
LAST_DAY(min(date)) mdate, mrr
FROM
ds_paylogs b
where b.mrr >0
GROUP BY
account_id
) b ON a.account_id = b.account_id
AND a.date = b.mdate
Result:
+------+----+----------+----+
| 1017 | 99 | 31-01-16 | 0 |
+------+----+----------+----+
| 1024 | 79 | 29-02-16 | 25 |
+------+----+----------+----+
I want to join these two results together into one view. I am stuck on how to do that?
Any advice on how to do that or how to simplify my queries is very much appreciated.
Update: Doing the below gets me what I need. However, it seems like there should be a more elegant solution to this.
SELECT
*
FROM
(
SELECT
a.paylog_id,
a.account_id,
a.date,
a.mrr
FROM
ds_paylogs a
INNER JOIN (
SELECT
account_id,
min(date) mdate,
mrr
FROM
ds_paylogs b
WHERE
b.mrr > 0
GROUP BY
account_id
) b ON a.account_id = b.account_id
AND a.date = b.mdate
) q
INNER JOIN (
SELECT
a.paylog_id,
a.account_id,
a.date,
a.mrr
FROM
ds_paylogs a
INNER JOIN (
SELECT
account_id,
LAST_DAY(min(date)) mdate,
mrr
FROM
ds_paylogs b
WHERE
b.mrr > 0
GROUP BY
account_id
) b ON a.account_id = b.account_id
AND a.date = b.mdate
) r ON q.account_id = r.account_id

Select average from join 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 |
+-----+------------+-------------+----------+--------------+--------------+-----+-------+--------+

How to retrieve records with duplicate in mysql

Im having problem retrieving the PLAYERs that has PLAYER_SCOREs that has duplicate PLAYER_SCORE. The criteria for PLAYER_SCORE to be considered duplicate it has other record that has the same P_ID, SCORE_1, SCORE_2, SCORE_3, and SCORE_4.
PLAYER TABLE:
+------+---------+
| P_ID | NAME |
+------+---------+
| 12 | Juan |
| 13 | Miguel |
| 14 | Luna |
| 15 | Placido |
+------+---------+
PLAYER SCORE TABLE
+-------+------+---------+---------+---------+---------+
| PS_ID | P_ID | SCORE_1 | SCORE_2 | SCORE_3 | SCORE_4 |
+-------+------+---------+---------+---------+---------+
| 1 | 1 | 87 | 96 | 79 | 93 |
| 2 | 1 | 87 | 96 | 97 | 88 |
| 3 | 1 | 87 | 96 | 79 | 93 |
| 4 | 2 | 85 | 84 | 85 | 94 |
| 5 | 2 | 87 | 96 | 22 | 44 |
| 6 | 2 | 85 | 84 | 85 | 94 |
| 7 | 3 | 79 | 96 | 82 | 84 |
| 8 | 3 | 97 | 96 | 92 | 95 |
| 9 | 3 | 87 | 96 | 97 | 87 |
| 10 | 4 | 89 | 75 | 99 | 97 |
| 11 | 4 | 97 | 96 | 92 | 95 |
| 12 | 4 | 87 | 96 | 97 | 87 |
+-------+------+---------+---------+---------+---------+
My sql scripts:
Script 1 :
SELECT P.P_ID, NAME FROM PLAYER P
INNER JOIN PLAYER_SCORE PS ON PS.P_ID = P.P_ID
GROUP BY P_ID, SCORE_1, SCORE_2, SCORE_3, SCORE_4
RESULT:
+------+---------+
| P_ID | NAME |
+------+---------+
| 1 | Juan |
| 1 | Juan |
| 2 | Miguel |
| 2 | Miguel |
| 3 | Luna |
| 3 | Luna |
| 3 | Luna |
| 4 | Placido |
| 4 | Placido |
| 4 | Placido |
+------+---------+
Script 2 :
SELECT P_ID, NAME FROM (
SELECT P.P_ID, NAME FROM PLAYER P
INNER JOIN PLAYER_SCORE PS ON PS.P_ID = P.P_ID
GROUP BY P_ID, SCORE_1, SCORE_2, SCORE_3, SCORE_4
) AS PLAYER GROUP BY P_ID
Result :
+------+---------+
| P_ID | NAME |
+------+---------+
| 1 | Juan |
| 2 | Miguel |
| 3 | Luna |
| 4 | Placido |
+------+---------+
Expected :
+------+--------+
| P_ID | NAME |
+------+--------+
| 1 | Juan |
| 2 | Miguel |
+------+--------+
Any help... Thanks.
You should keep only duplicates, so restrict output with HAVING:
SELECT P.P_ID, NAME FROM PLAYER P
INNER JOIN PLAYER_SCORE PS ON PS.P_ID = P.P_ID
GROUP BY P_ID, NAME, SCORE_1, SCORE_2, SCORE_3, SCORE_4
HAVING count(*) > 1
You can try this way :
SELECT P_ID, NAME FROM
PLAYER INNER JOIN
(
SELECT P_ID FROM PLAYER_SCORE
GROUP BY P_ID, SCORE_1, SCORE_2, SCORE_3, SCORE_4
HAVING COUNT(*) > 1
) AS SCORE ON SCORE.P_ID = PLAYER.P_ID

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