MySQL count based on condition from a different table - mysql

I have the following tables.
Table : types
--------------------
id | type
--------------------
1 | AA
--------------------
2 | BB
--------------------
3 | AA
--------------------
4 | BB
--------------------
Table : users
--------------------
id | username
--------------------
1 | abc
--------------------
2 | bcd
--------------------
3 | cde
--------------------
4 | def
--------------------
Table : methods
---------------------------------
id | user_id | details | type_id
---------------------------------
1 | 1 | detail_1 | 1
---------------------------------
2 | 1 | detail_2 | 3
---------------------------------
3 | 1 | detail_3 | 1
---------------------------------
4 | 1 | detail_4 | 3
---------------------------------
5 | 2 | detail_3 | 1
---------------------------------
6 | 2 | detail_5 | 2
---------------------------------
7 | 2 | detail_6 | 4
---------------------------------
8 | 2 | detail_2 | 3
---------------------------------
9 | 1 | detail_2 | 3
---------------------------------
10 | 1 | detail_2 | 3
---------------------------------
Desired Result :
---------------------------------------------------
UserName | No_of_AA_details | No_of_BB_details |
---------------------------------------------------
abc | 4 | 0 |
---------------------------------------------------
bcd | 2 | 2 |
---------------------------------------------------
I need to get the count of distinct details based on the type from types table.
I have tried this queries but max I am getting is all the counts and not the distinct values.
SELECT u.username,
CASE WHEN t.type = 'AA' THEN count(distinct m.details) END AS No_of_AA_details,
CASE WHEN t.type = 'BB' THEN count(distinct m.details) END AS No_of_BB_details
FROM users as u inner join methods as m on u.id = m.user_id inner join types as t on t.id = m.type_id
GROUP BY m.user_id
SELECT u.username,
SUM(t.type = 'AA') AS No_of_AA_details,
SUM(t.type = 'AA') AS No_of_BB_details
FROM users as u inner join methods as m on u.id = m.user_id inner join types as t on t.id = m.type_id
GROUP BY m.user_id
Any suggestions are welcome.

I can't test it right know but i think you had a good idea, can you try :
SELECT u.username,
m.user_id,
CASE
WHEN t.type = 'AA' THEN 1
ELSE 0
END AS No_of_AA_details,
CASE
WHEN t.type = 'BB' THEN 1
ELSE 0
END AS No_of_BB_details
FROM users as u
INNER JOIN methods as m on u.id = m.user_id
INNER JOIN types as t on t.id = m.type_id
and now you just need to do the sum :
SELECT u.username,
m.user_id,
SUM (CASE
WHEN t.type = 'AA' THEN 1
ELSE 0
END ) AS No_of_AA_details,
SUM (CASE
WHEN t.type = 'BB' THEN 1
ELSE 0
END ) AS No_of_BB_details
FROM users as u
INNER JOIN methods as m on u.id = m.user_id
INNER JOIN types as t on t.id = m.type_id
GROUP BY u.username, m.user_id

Related

Select records in one table and specific matching records from the other

I have three tables, two of which are relevant for this question. Users, Things, User_to_thing
Users
ID | Name | Active
-------------------
1 | Joe | 1
2 | Jack | 1
3 | Tom | 1
4 | Harry | 0
5 | Stan | 1
6 | Bob | 1
User_to_thing
Thing ID | User ID | Status
---------------------------
3 | 1 | 1
3 | 2 | 2
3 | 5 | 1
4 | 1 | 3
4 | 2 | 2
I'm trying to create a query where I can select all the active users in the users table and have a column where I can see the status for "thing 3" from the User_to_thing table while also sorting results so that the nulls come at the end. So the result would be something like:
User ID | Status
----------------
1 | 1
2 | 2
5 | 1
3 | NULL
6 | NULL
What I have so far for a query is the following:
SELECT u1.id, u1.name, user_to_thing.status
FROM users u1
LEFT JOIN user_to_thing ON u1.id = user_to_thing.user_id
WHERE u1.active = 1
OR user_to_thing.event_id = 62
ORDER BY (CASE WHEN user_to_thing.status = 1 THEN 1
WHEN user_to_thing.status = 2 THEN 2
ELSE 3 END)
What I'm getting as a result is the following:
User ID | Status | Thing ID
---------------------------
1 | 1 | 3
1 | 3 | 4
2 | 2 | 3
2 | 2 | 4
5 | 1 | 3
3 | NULL | NULL
6 | NULL | NULL
I'm not sure how to limit it to just thing #3 while also getting a list of all active users. Any guidance would be appreciated.
It looks like the following should work for you, grouping to remove duplicates and ordering based on null
select u.Id as UserId, t.status
from users u
left join User_to_thing t on t.UserID = u.id
where u.active = 1
group by u.Id, t.Status
order by case when status is null then 1 else 0 end, u.Id
Based on your revised data, you can amend slightly
select u.Id UserId, Min(t.status) Status
from users u
left join User_to_thing t on t.UserID=u.id
where u.active=1
group by u.Id
order by case when Min(t.status) is null then 1 else 0 end, u.Id

MySQL JOIN using more than one column and table

I have 3 tables that I need to JOIN, but I'm having difficulty getting the right result because I need information from more than 1 column. I wish to get all users that are available and has the status = 1. In addition, get both types 1 and 3. With users listed as type 3, I need to join with the other table (by user id) to get only users with a specific specialty listed on the other table.
My tables are similar to these:
users
id | status | availability | type
1 | 1 | 1 | 1
2 | 1 | 0 | 1
3 | 0 | 0 | 2
4 | 1 | 1 | 3
5 | 1 | 1 | 3
specialties
id | type
1 | 1
2 | 2
3 | 3
4 | 43
My relation table would look like this:
rel_users_specialties
id | id_user | id_specialty
1 | 1 | 29
2 | 2 | 3
3 | 4 | 3
4 | 5 | 3
My query would be:
SELECT *
FROM users u
JOIN rel_users_specialties r ON r.id_user = u.id
WHERE u.status = 1
AND u.disponibilidade = 1
AND r.id_specialty = 3
AND (u.type = 3 OR u.type = 1)
My expected result would be the following users (by id)
1, 4 and 5 (exclude user number 2 because of the availability = 0) and Although the user 1 has a specialty different than 3 it also has a type 1 (type one here would be a constant, regardless of the specialty selected).
Appreciate the help!
Set the conditions like this:
SELECT u.*
FROM users u INNER JOIN rel_users_specialties r
ON r.id_user = u.id
WHERE u.status = 1 AND u.availability = 1
AND ((u.type = 1) OR (u.type = 3 AND r.id_specialty = 3))
Or without a join:
SELECT u.*
FROM users u
WHERE u.status = 1 AND u.availability = 1
AND (
(u.type = 1)
OR
(u.type = 3 AND EXISTS(SELECT 1 FROM rel_users_specialties r WHERE r.id_user = u.id AND r.id_specialty = 3))
)
See the demo.

join tables to display posts of people who I follow

I want to display the posts of people who I follow
The 3 tables I have are:
Users:
+---------+------+
| id_user | name | last_logout
+---------+------+
| 1 | A | 22-02-2018 00:00:10
| 2 | B |
| 3 | C |
| 4 | D |
| 5 | E |
+---------+------+
Community:
+-------------+-------------+
| id_follower | id_followed |
+-------------+-------------+
| 1 | 2 |
| 1 | 3 |
| 1 | 5 |
+-------------+-------------+
Posts:
+---------+--------------+---------------+
| id_post | id_user_post | post | date
+---------+--------------+---------------+
| 1 | 2 | hi |
| 2 | 3 | hello |
| 3 | 5 | hey you |
| 4 | 4 | come on |
| 5 | 5 | where are you | 22-02-2018 00:01:00
+---------+--------------+---------------+
I'm using the following code but it doesn't return anything
SELECT u.name AS n
,p.post AS t
FROM community AS c
LEFT JOIN users AS u ON u.id_user = c.id_followed
LEFT JOIN posts AS p ON c.id_followed = p.id_user_post
WHERE u.id_follower = 1
Users.id_follower does not exist, so that is why you get nothing, in fact you are likely getting an error (Invalid column name 'id_follower'.).
Use Community.id_follower instead. I would also recommend using more descriptive column names (like 'username' and 'comment')
For the pure reason of answering your specific question, I have used 'n' and 't' in the query.
SELECT u.name as n, p.post as t
FROM Community c
LEFT JOIN Users u ON c.id_followed = u.id_user
LEFT JOIN Posts p ON c.id_followed = p.id_user_post
WHERE c.id_follower = 1
Test:
;WITH USERS AS(
SELECT *
FROM (VALUES (1,'A'),
(2,'B'),
(3,'C'),
(4,'D'),
(5,'E')) U(id_user, name))
, Community AS(
SELECT *
FROM (VALUES (1,2),
(1,3),
(1,5)) C(id_follower, id_followed))
, posts AS(
SELECT *
FROM (VALUES (1,2,'hi'),
(2,3,'hello'),
(3,5,'hey you'),
(4,4,'come on'),
(5,5,'where are you')) P(id_post, id_user_post, post))
SELECT u.name as n, p.post as t
FROM Community c
LEFT JOIN Users u ON c.id_followed = u.id_user
LEFT JOIN Posts p ON c.id_followed = p.id_user_post
WHERE c.id_follower = 1

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

Join tables multiple times on different rows in one result set

So I've got 2 tables (simplified below)
members documents
------------ ------------------
id | name | registered id | member_id | type | expiry
---------------------- ------------------------------
1 | AAA | 1234567890 1 | 1 | 1 | 1234567890
2 | BBB | 1234567890 2 | 1 | 2 | 1234567891
3 | CCC | 1234567890 3 | 1 | 3 | 1234567892
4 | 2 | 1 | 1234567893
5 | 2 | 2 | 1234567894
6 | 2 | 3 | 1234567890
and I need to display these like this:
member id | name | doc 1 expiry | doc 2 expiry | doc 3 expiry
--------------------------------------------------------------
1 | AAA | 1234567890 | 1234567891 | 1234567892
2 | BBB | 1234567893 | 1234567894 | 1234567895
I've tried querying with multiple outer joins and aliases but it's just repeating the document expiry timestamps. This is what I have so far:
SELECT DISTINCT `members`.`id`, `members`.`name`, `a`.`expiry` AS `expiry1`, `b`.`expiry` AS `expiry2`, `c`.`expiry` AS `expiry3`
FROM `members`
LEFT OUTER JOIN `documents` a ON `a`.`member_id` = `members`.`id`
LEFT OUTER JOIN `documents` b ON `b`.`member_id` = `members`.`id`
LEFT OUTER JOIN `documents` c ON `c`.`member_id` = `members`.`id`
GROUP BY `members`.`id`
People need to be able to search through this, for example to list everyone whose document type 3 has expired.
Try
SELECT
a.id AS 'member id',
a.name
SUM(a.d1exp) AS 'doc 1 expiry',
SUM(a.d2exp) AS 'doc 2 expiry',
SUM(a.d3exp) AS 'doc 3 expiry'
FROM
(
SELECT
aa.id,
aa.name,
COALESCE(d1.expiry, 0) AS d1exp,
COALESCE(d2.expiry, 0) AS d2exp,
COALESCE(d3.expiry, 0) AS d3exp
FROM
members aa
LEFT JOIN
documents d1 ON aa.id = d1.member_id AND d1.type = 1
LEFT JOIN
documents d2 ON aa.id = d2.member_id AND d2.type = 2
LEFT JOIN
documents d3 ON aa.id = d3.member_id AND d3.type = 3
) a
GROUP BY
a.id,
a.name
This is assuming the values in the 'expiry' field are numerical.