Select monthly counts of data across two tables in mysql - mysql

I have two tables, lastfm_scrobbles and lastfm_annotations. Example data:
mysql> select * from lastfm_scrobbles limit 5;
+---------+---------+-----------+---------------------+
| user_id | item_id | artist_id | scrobble_time |
+---------+---------+-----------+---------------------+
| 1469 | 45651 | 1 | 2010-06-30 13:57:42 |
| 1469 | 45651 | 1 | 2011-03-28 15:43:37 |
| 6872 | 45653 | 1 | 2013-08-03 15:07:44 |
| 7044 | 1370 | 1 | 2007-03-26 17:07:26 |
| 7044 | 1370 | 1 | 2007-08-24 18:41:35 |
+---------+---------+-----------+---------------------+
mysql> select * from lastfm_annotations limit 5;
+---------+---------+-----------+--------+------------+
| user_id | item_id | artist_id | tag_id | tag_month |
+---------+---------+-----------+--------+------------+
| 121 | 1330412 | 1330412 | 475 | 2006-12-01 |
| 121 | 1330412 | 1330412 | 517 | 2006-12-01 |
| 121 | 1330412 | 1330412 | 7280 | 2006-12-01 |
| 121 | 1330412 | 1330412 | 21384 | 2006-12-01 |
| 121 | 1330412 | 1330412 | 27872 | 2006-12-01 |
+---------+---------+-----------+--------+------------+
Furthermore, I have a user information table (lastfm_users). The details of this aren't important, but what is relevant is that the query:
select user_id from lastfm_users where scrobbles_recorded==1;
Returns the users I care about for the purposes of this question.
Ok, with that preamble out of the way: I need a query that will get me, for those users, the total number of entries they have in both the scrobbles and annotations tables for each month. In other words, the result should look something like:
user_id y m scrobble_count anno_count
123 2006 3 100 50
456 2008 11 321 10
... and so on
Make sense? I believe the query I want is a combination of the following:
select year(tag_month) as y, month(tag_month) as m, count(*) as anno_count
from lastfm_annotations where user_id in (select user_id from
lastfm_users where scrobbles_recorded=1)
group by user_id, year(tag_month), month(tag_month);
select year(scrobble_time) as y, month(scrobble_time) as m, count(*) as scrobble_count
from lastfm_scrobbles where user_id in (select user_id from
lastfm_users where scrobbles_recorded=1)
group by user_id, year(scrobble_time), month(scrobble_time);
But I'm not certain of the correct way to generate the join query to get the result I want. Suggestions?

You can try
select user_id, y, m,
coalesce(sum(case when source = 1 then total end), 0) anno_count,
coalesce(sum(case when source = 2 then total end), 0) scrobble_count
from
(
select 1 source, a.user_id, year(tag_month) y, month(tag_month) m, count(*) total
from lastfm_annotations a join lastfm_users u
on a.user_id = u.user_id
where u.scrobbles_recorded = 1
group by user_id, year(tag_month), month(tag_month)
union all
select 2 source, s.user_id, year(scrobble_time), month(scrobble_time), count(*)
from lastfm_scrobbles s join lastfm_users u
on s.user_id = u.user_id
where u.scrobbles_recorded = 1
group by user_id, year(scrobble_time), month(scrobble_time)
) q
group by user_id, y, m
or just
select user_id, y, m,
sum(case when source = 1 then 1 else 0 end) anno_count,
sum(case when source = 2 then 1 else 0 end) scrobble_count
from
(
select 1 source, a.user_id, year(tag_month) y, month(tag_month) m
from lastfm_annotations a join lastfm_users u
on a.user_id = u.user_id
where u.scrobbles_recorded = 1
union all
select 2 source, s.user_id, year(scrobble_time), month(scrobble_time)
from lastfm_scrobbles s join lastfm_users u
on s.user_id = u.user_id
where u.scrobbles_recorded = 1
) q
group by user_id, y, m;
Here is SQLFiddle demo

Related

selecting every newest row for specific values

Hi I have a table like so:
SN | User | is_borrowed | date
105 | 1 | 1 |2019-1-1
105 | 1 | 0 |2019-2-1
105 | 1 | 1 |2019-3-1
106 | 2 | 1 |2019-4-1
107 | 1 | 1 |2019-5-1
106 | 2 | 0 |2019-6-1
106 | 2 | 1 |2019-8-1
107 | 1 | 0 |2019-9-1
107 | 2 | 1 |2019-10-1
Wanted output is to show what is borrowed (not returned) and user=1:
SN | User | is_borrowed | date
105 | 1 | 1 |2019-3-1
Output for User=2 and borrowed (not returned):
SN | User | is_borrowed | date
106 | 2 | 1 |2019-8-1
107 | 2 | 1 |2019-10-1
In summary I want a list of devices currently borrowed that are not returned for each user. Sadly nothing comes to my mind tho :/
looking to your expected result seems you are looking for the max(date) for SN, user where is_borrowed = 1
select SN, user, is_borrowed, max(date)
from my_table
where is_borrowed = 1
group by SN, user, is_borrowed
or for the device actual borrowed
Select * from my_table m
inner join t (
select SN, is_borrowed, max(date) max_date
from my_table
where is_borrowed = 1
group by SN, is_borrowed
) t on t.SN = m.SN AND t.max_date = m.date
SELECT t.sn, t.user, t.is_borrowed, t.date
FROM TABLE_NAME t
WHERE t.is_borrowed = 1
AND t.date =
(
SELECT MAX(x.date)
FROM TABLE_NAME x
WHERE x.user = t.user
)
AND (
SELECT xx.is_borrowed
FROM TABLE_NAME xx
WHERE t.sn = xx.sn
AND t.date < xx.date
) <> 0
;

Calculate sum on the records while joining two tables with a third table

I have three tables:
mysql> select * from a;
+----+---------+
| ID | Name |
+----+---------+
| 1 | John |
| 2 | Alice |
+----+---------+
mysql> select * from b;
+------+------------+----------+
| UID | date | received |
+------+------------+----------+
| 1 | 2017-10-02 | 5 |
| 1 | 2017-09-30 | 1 |
| 1 | 2017-09-29 | 4 |
+------+------------+----------+
mysql> select * from c;
+------+------------+------+
| UID | date | sent |
+------+------------+------+
| 1 | 2017-09-25 | 7 |
| 1 | 2017-09-30 | 2 |
| 1 | 2017-09-29 | 3 |
+------+------------+------+
If I try to calculate the total number of sent for John, it would be 12. And for received, it would be 10.
But if I try to join all three tables, the result is weird. Here is my query to join three tables:
mysql> select sum(sent), sum(received) from a
-> join c on c.UID = a.ID
-> join b on b.UID = a.ID
-> where a.ID = 1;
+-----------+---------------+
| sum(sent) | sum(received) |
+-----------+---------------+
| 36 | 30 |
+-----------+---------------+
But I need correct numbers (12 and 10, respectively). How can I have correct numbers?
You should join the aggregated result and not the raw tables
select a.uid, t1.received, t2.sent
from a
inner join (
select uid, sum(received) received
from b
group by uid
) t1 on t1.uid = a.id
inner join (
select uid, sum(sent) sent
from c
group by uid
) t2 on t2.uid = a.id
where a.id = 1
You could try below
select bx.id, recieved, sum(c.sent) sent from
(
SELECT a.id, sum(b.received) recieved
from a
INNER JOIN b
ON a.id=b.uid
group by a.id
) bx
INNER JOIN c
ON c.uid=bx.id
group by bx.id, bx.recieved;
>>>Demo<<<
This gets rid of the subquery, but introduces something else you might not want:
( SELECT uid, 'Received' AS direction, SUM(received) AS HowMany
WHERE uid = 1
GROUP BY uid )
UNION ALL
( SELECT uid, 'Sent' AS direction, SUM(sent) AS HowMany
WHERE uid = 1
GROUP BY uid )

mysql get user rank using inner join

I have three tables as following. And i want to get user with highest rank.
1) users table as
id | user_id | created_at
1 | 100 | 2014-11-07 02:54:09
2 | 102 | 2014-11-08 03:52:40
3 | 103 | 2014-11-10 02:47:26
4 | 104 | 2014-11-11 02:54:48
5 | 105 | 2014-11-14 03:11:23
6 | 105 | 2014-11-15 00:56:34
2) user_profile table as
id | user_id | rank
1 | 100 | 100
2 | 102 | 500
3 | 103 | 10
4 | 104 | 0
5 | 105 | 11
6 | 105 | 1000
3) user_followers table as
id | user_id | followers
1 | 100 | 10
2 | 102 | 20
3 | 103 | 30
4 | 104 | 40
5 | 105 | 0
6 | 105 | 50
Now my query is i want to get list of users short by highest rank in table2. In case of tie user with the highest followers in table3 will win. In case of same followers user who is created first will win.
And another one i want to find user rank with same logic passing by user id.
I already tried something like
SET #i=0;
SELECT user_id, rank, #i:=#i+1 AS rank FROM user_profile ORDER BY rank DESC
Arion's answer looked like this...
SELECT
users.*
FROM
users
JOIN user_profile
ON users.user_id = user_profile.user_id
JOIN user_followers
ON user_profile.user_id=user_followers.user_id
ORDER BY
user_profile.rank DESC,
user_followers.followers DESC,
users.created_at DESC
...but this seems a little closer to what you're after...
SELECT u.user_id
, u.created_at
, up.rank
, uf.followers
, #i:=#i+1 corrected_rank
FROM users u
LEFT
JOIN user_profile up
ON up.user_id = u.user_id
LEFT
JOIN user_followers uf
ON uf.user_id = u.user_id
CROSS
JOIN (SELECT #i:=1) v
ORDER
BY rank DESC
, followers DESC
, created_at ASC;
SET #rank = 0;
SELECT
#rank := #rank + 1 AS rank, *
FROM
(
SELECT users.user_id, user_profile.rank, user_followers.followers, users.created_at
FROM users
LEFT JOIN user_profile ON users.user_id = user_profile.user_id
LEFT JOIN user_followers ON users.user_id = user_followers.user_id
ORDER BY user_profile.rank DESC, user_followers.followers DESC, users.created_at ASC
)

MySQL join and sum issue / combine queries

I have created a points example to demonstrate my issue.
A members can reward other members points, I am trying to build a query which will display the points a user has and points user has given.
Database Example
Members,
+----+----------+
| id | username |
+----+----------+
| 1 | user1 |
| 2 | user2 |
| 3 | user3 |
+----+----------+
Points,
+-------+--------+--------+
| IDFor | IDFrom | Pointz |
+-------+--------+--------+
| 1 | 2 | 5 |
| 1 | 2 | 5 |
| 3 | 1 | 2 |
+-------+--------+--------+
The return I am looking for is,
+-----------+--------+-------+
| username | Pointz | Given |
+-----------+--------+-------+
| user1 | 10 | 2 |
| user2 | 0 | 10 |
| user3 | 2 | 0 |
+-----------+--------+-------+
Both my queries return,
+-----------+--------+-------+
| username | Pointz | Given |
+-----------+--------+-------+
| user1 | 10 | 4 |
| user2 | 0 | 10 |
| user3 | 2 | 0 |
+-----------+--------+-------+
http://sqlfiddle.com/#!2/32ae6/6
SELECT a.`username`, sum(a.`Pointz`), sum(b.`Pointz`) FROM
(SELECT * FROM `members`
LEFT JOIN `Example`.`Points` AS p ON `members`.`id` = p.`IDFor` ) AS a
LEFT JOIN
(SELECT * FROM `members`
LEFT JOIN `Example`.`Points` AS n ON `members`.`id` = n.`IDFrom` ) AS b
ON a.id = b.id
GROUP BY a.`id`
http://sqlfiddle.com/#!2/32ae6/7
SELECT `members`.`username`,sum(p.`Pointz`),sum(n.`Pointz`)
FROM `members`
LEFT JOIN `Example`.`Points` as p ON p.`IDFor` = `members`.`id`
LEFT JOIN `Example`.`Points` as n ON n.`IDFrom` = `members`.`id`
GROUP BY `members`.`id`
Seems to be a common question that pops up but have not found a solution, all my other attempts from similar questions have not ended well, Thanks all.
This is what u want
select a.username, ifnull(Pointz, 0) Pointz, ifnull(Given, 0) Given from
(SELECT id, `username`, sum(`Pointz`) Pointz FROM `members`
LEFT JOIN `Points` ON `members`.`id` = `Points`.`IDFor` group by id) a
left join
(SELECT id, `username`, sum(`Pointz`) Given FROM `members`
LEFT JOIN `Points` ON `members`.`id` = `Points`.`IDFrom` group by id) b
on a.id = b.id
Try:
SELECT m.username,
COALESCE( pr.preceived, 0 ) as Pointz,
COALESCE( pg.pgiven, 0 ) as Given
FROM members m
LEFT JOIN ( SELECT IDFor, sum(pointz) as preceived
FROM Points
GROUP BY IDFor ) pr
ON m.id = pr.IDFor
LEFT JOIN ( SELECT IDFrom, sum(pointz) as pgiven
FROM Points
GROUP BY IDFrom ) pg
ON m.id = pg.IDFrom
http://sqlfiddle.com/#!2/32ae6/48
Try this:
SELECT m.`username`,
ifnull((SELECT sum(`Pointz`) FROM Points p
WHERE p.IDFor = m.id ), 0),
ifnull((SELECT sum(`Pointz`) FROM Points p
WHERE p.IDFrom = m.id ), 0)
FROM Members m
SQLFiddle

Joining tables and making count operation - MySQL

I have those tables:
Members
---------------------------
MemberID | Name |.....
1
2
3
4
---------------------------
RentedMovies
---------------------------
MemberID | MovieID | DateOfLease | ReturnDate | .....
1 | 1 | 2012-12-20 | 2013-01-05
1 | 2 | 2012-12-15 | 2012-12-30
1 | 3 | 2012-12-16 | 2013-01-06
2 | 1 | 2012-12-17 | 2012-12-18
2 | 4 | 2012-12-18 | 2013-01-05
3 | 1 | 2012-12-19 | 2013-01-04
I need to get this:
--------------------------------------------------------
MemberID | NumberOfRentedMovies | ReturnData < curdate())
1 | 3 | 1
2 | 2 | 1
3 | 1 | 0
4 | 0 | 0
---------------------------------------------------------
And i used next code:
SELECT Members.MemberID,
COUNT(rented.MemberID) AS NumberOfRentedMovies,
COUNT(notTakenBackOnTime.idClana) AS NumberOfMoviesLate
FROM Members
left JOIN RentedMovies as rented ON rented.MemberID = Members.MemberID
left JOIN RentedMovies as notTakenBackOnTime ON notTakenBackOnTime.MemberID
= Members.MemberID AND notTakenBackOnTime.ReturnDate< CURDATE()
group by Members.MemberID
But it doesnt work corrextly!
And I also tried with this:
SELECT MemberID,my,my2
FROM Members as mem
JOIN (SELECT COUNT(* )AS my FROM RentedMovies) b
ON b.MemberID = mem.MemberID
JOIN (SELECT COUNT(* )AS my2 FROM RentedMovies WHERE ReturnDate< CURDATE()) c
ON c.MemberID = mem.MemberID
But i got some errors!
So the question is how to accomplish right solution?
You were close. Try this:
SELECT M.MemberID,
COUNT(RM.MemberID) NumberOfRentedMovies,
SUM(CASE WHEN RM.ReturnDate < CURDATE() THEN 1 ELSE 0 END) ReturnData
FROM Members M
LEFT JOIN RentedMovies RM
ON M.MemberID = RM.MemberID
GROUP BY M.MemberID
The desired result you showed can be accomplished by:
SELECT MemberID,
COALESCE(COUNT(MovieID), 0) AS NumberOfRentedMovies,
COALESCE(SUM(ReturnDate < CURDATE()), 0) AS NotYetReturned
FROM Members
LEFT JOIN RentedMovies USING (MemberID)
GROUP BY MemberID
See it in action: http://sqlfiddle.com/#!2/a192c/1