SQL Sorting with Two Joined Tables - mysql

I have these two tables
people
============
id, name
and
answer_sheets
============
id, person_id, answer, date_answered
person_id is a foreign key from people.id
Now, what I wanted to do is to sort people in such in order basing it on the latest answer_sheets.date_answered (we can derive that one people row can have many answer_sheets rows)
Say for example we have the tables
people
============
id name
1 Person1
2 Person2
3 Person3
4 Person4
5 Person5
answer_sheets
=============
id person_id answer date_answered
1 1 string JUN 13
2 2 string JUN 15
3 3 string JUN 17
4 2 string JUN 18
5 1 string JUN 19
6 3 string JUN 20
7 2 string JUN 25
and I wanted to order people in ASC order based on a people row's answer_sheets.date_answered
the output must be
=============
id name last_date_answered
4 Person4 NIL
5 Person5 NIL
1 Person1 JUN 19
3 Person3 JUN 20
2 Person2 JUN 25
You can observe that people with ids 4 and 5 does not have an answer_sheet and yet they should be included in the list.
Question: What must be the appropriate SQL query for this? Thanks.

To get records to display even if there is no match, you can use a LEFT JOIN.
SELECT p.id, p.name, MAX(a.date_answered)
FROM people p
LEFT JOIN answer_sheets a on p.id = a.personID
GROUP BY p.id, p.name
ORDER BY MAX(date_answered) ASC
And, if you want to try it out, or play with it more, I made a SQLFiddle...

SELECT
people.id,
people.name,
baseview.last_date_answered
FROM (
SELECT
person_id,
MAX(date_answered) AS last_date_answered
FROM answer_sheets
ORDER BY IFNULL(MAX(date_answered),'0001-01-01')
) AS baseview
INNER JOIN people ON bseview.person_id=people.id

SELECT *
FROM people
CROSS APPLY ( SELECT MAX(date_answered) MaxDate
FROM answer_sheets
WHERE answer_sheets.PersonID = people.ID
) L

Related

How to select one column with all distinct values based on some clause

I essentially like to have one query which I'll execute one time and like to have the result (no multiple query execution) and definitely, the query should use simple MySQL structure (no complex/advanced structure to be used like BEGIN, loop, cursor).
Say I've two tables.
1st Table = Country (id(PK), name);
2nd Table = Businessman (id(PK), name, city, country_id(FK))
Like to SELECT all countries, whose businessmen are from distinct cities. No two businessmen exist in one country, who are from the same city. If so, that country will not be selected by the SELECT clause.
Country
id name
1 India
2 China
3 Bahrain
4 Finland
5 Germany
6 France
Businessman
id name city country_id
1 BM1 Kolkata 1
2 BM2 Delhi 1
3 BM3 Mumbai 1
4 BM4 Beijing 2
5 BM5 Paris 6
6 BM6 Beijing 2
7 BM7 Forssa 4
8 BM8 Anqing 2
9 BM9 Berlin 5
10 BM10 Riffa 3
11 BM11 Nice 6
12 BM12 Helsinki 4
13 BM13 Bremen 5
14 BM14 Wiesbaden 5
15 BM15 Angers 6
16 BM16 Sitra  3
17 BM17 Adliya 3
18 BM18 Caen 6
19 BM19 Jinjiang 2
20 BM20 Tubli 3
21 BM21 Duisburg 5
22 BM22 Helsinki 4
23 BM23 Kaarina 4
24 BM24 Bonn 5
25 BM25 Kemi 4
In this respect, China and Finland shouldn't be listed.
I've attempted using count and group by, but no luck.
Can you please help me to build up this query.
Here it is, all you need is to join Businessman table and count cities and distinct cities and if they equal that means all businessmen are from different cities:
SELECT
c.`id`,
c.`name`,
COUNT(b.`id`) AS BusinessmanCount,
COUNT(b.`city`) AS CityCount,
COUNT(DISTINCT b.`city`) AS DistinctCityCount
FROM `countries` c
INNER JOIN Businessman b ON c.`id` = b.`country_id`
GROUP BY c.`id`
HAVING CityCount = DistinctCityCount
For minified version what you exactly need:
SELECT
c.`id`,
c.`name`
FROM `countries` c
INNER JOIN Businessman b ON c.`id` = b.`country_id`
GROUP BY c.`id`
HAVING COUNT(b.`city`) = COUNT(DISTINCT b.`city`)
Well, I think we should have waited for you to show your own query, because one learns best from mistakes and their explanations. However, now that you've got answers already:
Yes, you need group by and count. I'd group by cities to see if I got duplicates. Then select countries and exclude those that have duplicate cities.
select *
from country
where id not in
(
select country_id
from businessmen
group by city, country_id
having count(*) > 1
);
You need either nested aggregations:
select *
from Country
where id in
(
select country_id
from
(
select city, country_id,
count(*) as cnt -- get the number of rows per country/city
from Businessman
group by city, country_id
) as dt
group by country_id
having max(cnt) = 1 -- return only those countries where all counts are unique
)
Or compare two counts:
select *
from Country
where id in
(
select country_id
from Businessman
group by country_id
having count(*) = count(distinct city) -- number of cities is equal to umber of rows
)

Multiple Counts from many INNER JOIN tables with Conditions

I'm having a lot of trouble figuring out how to write this query. Here's an exmaple of the data set and what I need to query:
**System Table**
SystemID Active
1 T
2 T
3 T
4 F
5 F
6 F
**BlogPost Table**
BlogPostID SystemID Create_Month
100 2 Jan
101 2 Jan
102 2 Feb
103 3 Feb
104 3 Mar
105 6 Mar
106 6 Mar
**Comment Table**
Comment ID BlogPostID Liked
201 100 T
202 100 T
203 100 T
204 102 T
205 102 T
206 102 T
207 103 F
So, In words, I'm trying to get: By month, show me all the active systems who created a post during that month, the number of posts they made in aggregate, and the count of the subset of those posts who had a comment that was like.
The end result would be like:
Column 1 - Month
Column 2 - Count of Active Systems where a Post Created in Month
Column 3 - Count of Posts Applicable to those systems
Column 4 - Count of Applicable Posts that had comments that were liked
I don't even know where to start really. My terrible "this is obviously wrong" attempt is below. Any help is much appreciated, thanks!
SELECT
Month,
COUNT(DISTINCT system.systemid),
COUNT(blogpost.BlogPostID)
COUNT(comments.commentiD)
FROM
system INNER JOIN
blogpost ON system.systemid = blogpost.systemid INNER JOIN
comments ON blogpost.BlogPostID = comment.BlogPostID
WHERE
system.active = T
AND comments.like = T
GROUP BY month
A complicated one !
SELECT
b.Create_Month,
COUNT(DISTINCT s.SystemID) as SystemCount,
COUNT(DISTINCT b.BlogPostID) as PostsCount,
COUNT(DISTINCT t.BlogPostID) as PostsWithLike
FROM System s
JOIN BlogPost b
ON s.systemID = b.systemID
AND s.Active = 'T'
LEFT JOIN Comment c
ON b.BlogPostID = c.BlogPostID
LEFT JOIN
(
SELECT DISTINCT c.BlogPostID as BlogPostID
FROM
Comment c
GROUP BY c.BlogPostID
HAVING SUM(if(c.Liked='T',1,0))>0
) as t
ON b.BlogPostID = t.BlogPostID
GROUP BY b.Create_Month
This is probably what you want :
SELECT s.systemid, active, bp.create_month, bp.systemid, COUNT(bp.blogpostid), COUNT(c.liked)
FROM system AS s
LEFT OUTER JOIN Blogpost AS bp ON s.systemid = bp.systemid
LEFT OUTER JOIN Comment AS c ON bp.blogpostid = c.blogpostid
WHERE active = 'T' AND c.Liked = 'T' GROUP BY s.systemid,bp.create_month

My sql query with two tables

I have two tables named person and person_sibling. The person_sibling table contains the sibling id which refer to the sibling of the person( For ex: sibling of the person SANGEETHA is SURESH). I need to get all the names whose age is older than their sibling age. The table data is shown below
Person table:
NAME AGE FNAME ID GENDER
SANGEETHA 20 PONNURANGAM 2 FEMALE
SARANYA 22 CHOKALINGAM 3 FEMALE
KANNA 22 ALAGRI 4 MALE
LAVANYA 21 MUNISWAMI 1 FEMALE
SURESH 25 PONNURANGAM 20 MALE
SARALA 26 CHOKALINGAM 21 FEMALE
KARAN 20 ALAGRI 2 MALE
ARTHI 20 ALAGRI 25 FEMALE
person_sibling table:
ID SIBLING_ID
2 20
3 21
4 25
4 22
20 2
21 3
25 4
22 4
22 25
25 22
I've tried this:
SELECT name
FROM person p , person_sibling s
where p.id=s.sibling_id and p.age <=(select age from person where id=s.sibling_id)
But I can't able to get it. Can someone help please
SELECT p.name
FROM person p
inner join person_sibling s on p.id = s.id
inner join person sp on s.sibling_id = sp.id
where p.age > sp.age
A left join can give you all people that don't have an older sibling, it'll join to find all older siblings and a null check will just give you the rows where none exists.
SELECT DISTINCT p.* FROM person p
LEFT JOIN person_sibling ps ON p.id = ps.id
LEFT JOIN person s ON ps.sibling_id = s.id AND s.age > p.age
WHERE s.id IS NULL;
An SQLfiddle to test with.

mysql, merge data of two columns into one

i have a table like this
id genre genre2
1 25 0
2 12 25
3 25 12
4 18 17
5 19 14
and i want to count the different genres id and the count of them in both columns but merged into one
and want a result like this
genre count
25 3
12 2
18 1
19 1
17 1
14 1
0 1
i have tried unions, and counts, and everything i think of, but i cant achieve to get the result i want, the closest was making two querys and UNION them, but it doesnt work like i want
any ideas? thanks for the help
You must use UNION ALL instead UNION.
SELECT
genre, COUNT(*) cnt
FROM
(SELECT genre FROM tbl
UNION ALL
SELECT genre2 FROM tbl) a
GROUP BY genre
ORDER BY cnt DESC
You can try it on SQL FIDDLE

MySQL Join Multiple (More than 2) Tables with Conditions

Assume I have 4 tables:
Table 1: Task
ID Task Schedule
1 Cut Grass Mon
2 Sweep Floor Fri
3 Wash Dishes Fri
Table 2: Assigned
ID TaskID (FK) PersonID (FK)
1 1 1
2 1 2
3 2 3
4 3 2
Table 3: Person
ID Name
1 Tom
2 Dick
3 Harry
Table 4: Mobile
ID PersonID (FK) CountryCode MobileNumber
1 1 1 555-555-5555
2 2 44 555-555-1234
3 3 81 555-555-5678
4 3 81 555-555-0000
I'm trying to display the
Task on a certain day
Name of person assigned to task
Phone numbers of said person
I think it should be something like the following, but I'm not sure how to set up the conditions so that the results are limited correctly:
SELECT T.ID, T.Task, P.Name, M.MobileNumber
FROM Task AS T
LEFT JOIN Assigned AS A
ON T.ID = A.TaskID
LEFT JOIN Person AS P
ON A.PersonID = P.ID
LEFT JOIN Mobile AS M
ON M.PersonID = P.ID
WHERE T.Schedule = Fri
My goal is to fetch the following information (it will be displayed differently):
Tasks Name MobileNumber
Sweep Floor, Wash Dishes Dick, Harry 44-555-555-1234, 81-555-555-5678, 81-555-555-0000
Of course, if JOIN is the wrong way to do this, please say so.
It's unclear what you want to do with duplicate data in this case, but you should be looking at using inner joins instead of outer joins, and using something like group_concat() to combine the phone numbers.