Mysql select id from table1 and select count(id) from table2 - mysql

I have two tables. I want to select id from table 1 and count the same from table2
Table 1
Id qId opt
1 30 Chris Christie
2 30 Hillary Clinton
3 30 Allan West
4 30 Joe Biden
5 31 Mark
6 31 Ben Johnson
Table2
poll_id qId ansId
201 30 1
202 30 2
204 31 8
The below query i tried, outputs only the ansId 1 and 2 since there is no 3 and 4 in Table2.
SELECT a.Id,
a.opt,
COUNT(b.ansId)
from Table1 a
INNER JOIN Table2 b ON a.Id = b.ansId
where a.qId =30
But i need all ansId 1,2,3,4 with count of 3 and 4 as 0 as given below.
Id opt COUNT(b.ansId)
1 Chris Christie 1
2 Hillary Clinton 1
3 Allan West 0
4 Joe Biden 0

First thing your are missing with group by ,count is an aggregate function and this needs to be grouped,second you need to use left join with an additional condition in on clause i.e and a.qId =30 so it will stil gives you the result if left id is not found in right table,using where clause will filter out the whole resultset while if you use additional condition in join this will only filter the records from the right table
SELECT a.Id,
a.opt,
COUNT(b.ansId) from Table1 a
LEFT JOIN Table2 b ON a.Id = b.ansId and a.qId =30
GROUP BY a.Id
Fiddle Demo
Edit after sample dataset is updated
SELECT a.Id,
a.opt,
COUNT(b.ansId) from Table1 a
LEFT JOIN Table2 b ON a.Id = b.ansId
WHERE a.qId =30
GROUP BY a.Id
Fiddle demo 2

Related

SQL: elegant way to get first, second, and third degree associations

I have tables named course, student and students_in in a MySQL database. The tables look like this:
course
course_id name
3 Physics
12 English
19 Basket Weaving
4 Computer Science
212 Discrete Math
102 Biology
20 Chemistry
50 Robotics
7 Data Engineering
student
id name
2 Sally
1 Bob
17 Robert
9 Pierre
12 Sydney
41 James
22 William
5 Mary
3 Robert
92 Doris
6 Harry
students_in
course_id student_id grade
3 2 B
212 2 A
3 12 A
19 12 C
3 41 A
4 41 B
212 41 F
19 41 A
12 41 B
3 17 C
4 1 A
102 1 D
102 22 A
20 22 A
20 5 B
50 3 A
12 92 B
12 17 C
7 6 A
Here is a Fiddle: http://sqlfiddle.com/#!17/8d86ee/34
My goal is to get the id and name of the students who:
have taken a course with Sally (i.e. "first-degree" relationship), OR
have taken a course with someone who has taken a course with Sally (i.e. "second-degree" relationship), OR
have taken a course with someone who has taken a course with someone who has taken a course with Sally (i.e. "third-relationship" relationship)
Essentially, we're looking for first-, second-, and third-degree relationships to Sally.
Here is a depiction of what this looks like:
Since Sally took course IDs 3 and 212, the desired result would look like this (not the colorful table above, which I provided for illustration of the logic involved):
student_id student_name
12 Sydney <-- took course ID 3 with Sally
41 James <-- took course ID 3 and 212 with Sally
17 Robert <-- took course ID 3 with Sally
1 Bob <-- took course ID 4 with James
92 Doris <-- took course ID 12 with James and Robert
102 William <-- took course ID 102 with Bob
I tried to solve this problem by using a Common Table Expression (CTE) to query the first-degree relationships, and can probably use two additional CTEs to get the second-degree and third-degree relationships. But, this feels like a very inelegant way to do this.
Can someone please help with an elegant approach to this problem?
Thank you!
You can use a recursive cte:
with recursive cte(cid, sid, name, l) as (
select si.course_id, si.student_id, s.name, 1 from students_in si
join student s on s.id = si.student_id where si.course_id in (select si1.course_id
from students_in si1 join student s1 on s1.id = si1.student_id and s1.name = 'Sally') and s.name != 'Sally'
union all
select si.course_id, si.student_id, s.name, c.l + 1 from cte c
cross join students_in si
join student s on s.id = si.student_id
where si.course_id in (select si1.course_id
from students_in si1 where si1.student_id = c.sid) and si.course_id != c.cid and si.student_id != c.sid and c.l < 3
)
select distinct sid, name from cte where name != 'Sally'
See fiddle.
With Recursive coursemates As (
Select y.student_id, 1 as removal
From students_in x Inner Join students_in y
On x.course_id=y.course_id
Where x.student_id=2
UNION
Select y.student_id, r.removal+1
From coursemates r Inner Join students_in x
On r.student_id=x.student_id
Inner Join students_in y
On x.course_id=y.course_id
Where removal<=2
)
Select c.student_id, min(c.removal) as howfar, min(s.name) as student_name
From coursemates c Left Outer Join student s
On c.student_id=s.student_id
Where student_id <> 2
Group By c.student_id
Order by 2, 1
A little verbose, but also a little more generalized than your try in that you can control the depth.
A few defensive additions: 1. Left join on student table in case no R.I. there. 2. Filter out Sally from the result (don't care that Robert was with Sally and then Sally was with Robert)
Join's repeated as many times as needed, also good, but perhaps less elegant:)
with rel as ( --join student->student thru course
select t1.student_id s1Id, t2.student_id s2Id
from students_in t1 inner join students_in t2
on t2.course_id=t1.course_id
where t2.student_id<>t1.student_id
group by t1.student_id,t2.student_id
)
,four as(
select t1.s1Id as s1Id1 ,t2.s1Id s2Id1,t2.s2Id s2Id2 ,t3.s2Id s3Id2
from rel t1 left join rel t2 on t2.s1Id=t1.s2Id and t2.s2Id<>t1.s1Id
left join rel t3 on t3.s1Id=t2.s2Id and t2.s2Id<>t1.s1Id
and t3.s2Id<>t1.s1Id
where t1.s1Id=2
group by t1.s1Id ,t2.s1Id,t2.s2Id,t3.s2Id
)
select t1.s1Id1,t1,s3Id2,s1.name,s3.name,s4.name,s6.name
from four t1
inner join student s1 on t1.s1Id1=s1.id
inner join student s3 on t1.s2Id1=s3.id
inner join student s4 on t1.s2Id2=s4.id
inner join student s6 on t1.s3Id2=s6.id

SQL inner join with max function by groub

I have some problem from using the inner join with group by using max function.
my detail :
Table inventory
site_ID tank_number volume times-tramp ID
1 1 5000 06/08/2017 15:00 1
1 1 4900 06/08/2017 15:01 2
1 2 6000 06/08/2017 15:05 3
1 3 4000 06/08/2017 15:05 4
2 1 3000 06/08/2017 15:33 5
2 2 2000 06/08/2017 15:34 6
1 1 4800 06/08/2017 15:36 7
1 2 5800 06/08/2017 16:00 8
Table wp_users (wordpress)
ID Name
1 aaa
2 bbbb
Now, I using with wpdatatable plugin in wordpress so i want use the inner join and group with tank_number and using data update by times-strap
The result should be is :
When user "aaa" login then ID will is 1
the result that want to show.
site_ID tank_number volume times-tramp
1 1 4800 06/08/2017 15:36
1 2 5800 06/08/2017 16:00
1 3 4000 06/08/2017 15:05
But
I got the this result :
site_ID tank_number volume times-tramp
1 1 5000 06/08/2017 15:00
1 2 6000 06/08/2017 15:05
1 3 4000 06/08/2017 15:05
So can every one help to advise me so I have show my code the showing the error due to i can't join with 2 table by correct syntax sql.
this code can work without inner join
select site_id, tank_product, volume, timestramp from inventory as t1
inner join (
select tank_product as tank, max(timestramp) as time from inventory
where site_id=1 group by tank_product) as t2
on t1.tank_product = t2.tank and t1.timestramp = t2.time and t1.site_id=1
and Now I trying to using with inner join but not work now.
SELECT inventory.site_id,
inventory.tank_product,
inventory.volume,
inventory.timestramp,
wp_users.ID
FROM inventory as t1
INNER JOIN wp_users
(SELECT inventory.tank_product, max(inventory.timestramp) as time from inventory
WHERE inventory.site_id=wp_users.ID GROUP BY inventory.tank_product) as t2
ON t1.inventory.tank_product=t2.tank AND t1.inventory.timestramp=t2.time AND t1.inventory.site_id=wp_users.ID
Can advise me for correct way to use the inner join by group by max function.
So, the schema you present and the queries you provided don't line up (naming is all over the place). It would be very helpful if you provided a sql fiddle to help present your problem (at least in the future).
In any event, I think you were close:
select t2.site_id, t2.tank_product, t1.volume, t2.time
from (
select site_id, tank_product, max(timestramp) as time
from inventory
group by site_id,tank_product) t2
inner join inventory t1
on t2.site_id=t1.site_id and t1.tank_product=t2.tank_product and t2.time=t1.timestramp
inner join wp_users u
on u.id=t2.site_id
where u.id=1
order by t2.site_id,t2.tank_product asc
(Assuming you pass the wp_users.id into the query; I've hard-coded that with u.id=1.)
fiddle
Try to run this:
SELECT i1.site_ID, i1.tank_product, i1.volume, i.timestramp, iu.User_ID
FROM Inventory AS i1
INNER JOIN (
SELECT u.ID AS UserID, i.tank_product, MAX (i.timestramp) AS time
FROM Inventory AS i2
INNER JOIN wp_users AS u
ON i2.site_id = u.ID
GROUP BY u.ID, i.tank_product
) as iu
ON i1.tank_product = iu.tank_product
AND i1.timestramp = iu.time
AND i1.site_ID = iu.UserID;

MYSQL Get lowest value in column of a group specified by another column

I have a table that looks like this:
id name yearofstudy mark
1 Alain A 2 75
2 Michael B 3 85
3 Chen C 1 55
4 Caroline D 2 60
5 Mohamed E 2 60
6 Alex F 1 55
7 Sofia O 3 78
8 Samir O 1 85
9 Rob G 2 78
10 Big K 3 55
And I'm trying to get the id, name, year and mark of the students with the lowest (and highest) mark in each year which would give:
id name yearofstudy mark
3 Chen C 1 55
4 Caroline D 2 60
10 Big K 3 55
SQL isn't my strong point and I've been trying using the MIN() function but I haven't managed to get it right yet and would really appreciate some help.
Using a subquery to get the min() and max() for each yearofstudy, and joining it to the original table. (You did say you wanted lowest and highest, right?)
select t.id, t.name, t.yearofstudy, t.mark
from t
inner join (
select
yearofstudy
, min(mark) as minMark
, max(mar) as maxMark
from t
group by yearofstudy
) as m
on t.yearofstudy = m.yearofstudy
and (t.mark = minMark or t.mark = maxMark)
or for just the lowest mark per year:
select t.id, t.name, t.yearofstudy, t.mark
from t
inner join (
select
yearofstudy
, min(mark) as minMark
from t
group by yearofstudy
) as m
on t.yearofstudy = m.yearofstudy
and t.mark = minMark
You could write the query as follows:
SELECT t1.* from your_table t1
INNER JOIN (
SELECT yearofstudy, MIN(marks) as marks
FROM your_table GROUP BY yearofstudy
) t2
ON t1.yearofstudy = t2.yearofstudy
AND t1.marks = t2.marks
GROUP BY t1.yearofstudy
ORDER BY t1.yearofstudy, t1.id;
If all the MIN records for the yearofstudy are required, then you could simply remove GROUP BY t1.yearofstudy
Demo

Remove duplicates in Join statement in mysql and group

I have two tables
table1
Name marks
John 50
Smith 70
Adam 60
Roy 70
table2
Score Grade other
50 C 1.5
60 B 0.7
70 A 0.8
70 A 1.0
I want to get how many people have got A, B, C passes
I want to get an output as
Grade Count
C 1
B 1
A 2
Query I tried was
SELECT table2.Grade,
COUNT(DISTINCT table2.Grade) as count
FROM table1
LEFT JOIN table2
ON table1.Mark = table2.Score
GROUP BY table2.Grade;
But it Gives
Grade Count
C 1
B 1
A 4
So How to remove the duplicates ?
Please help.
At your second table, you got duplicate rows:
Score Grade other
50 C 1.5
60 B 0.7
70 A 0.8
70 A 1.0
Here, there are to A's, and when you joing with first table according to the field "Grade--Score", the whole join is:
Jhon 50 C
Smith 70 A
Smith 70 A --> Second A from second table
Adam 60 B
Roy 70 A
Roy 70 A --> Second A from second table
So group by and count will result 4 for the field grade here:
A 4 --> 2 Smith and 2 Roy
B 1
C 1
So, to get how many single person per grade:
select tb2.Grade GradeMark, count(*) TotalPersons
from table1 as tb1
left join (select tbi2.Score, distinct(tbi2.Grade), tbi2.other, from table2 tbi2) as tb2 on tb2.Grade = tb1.marks
group by tb2.Grade
This query will select distinct values from table2, join with table one and count the results per grade so you should get:
A 2
B 1
C 1
You don't need a JOIN for this. You can try like below using a simple group by and get the count()
select Grade, count(*) as `Count`
from table2
group by Grade;

MySql Count with Join

I have two tables -
Users_tag (userID,tagID)
tagId - userId
1 1
2 1
3 2
4 2
5 4
Tags (id,tagText)
id tagText
1 dog
2 cat
3 lion
4 tiger
5 chicken
I want my query to return tagId,TagText and count of each row based on userId.
Any help please...
SELECT a.id, a.tagText, COUNT(b.tagID) totalCount
FROM Tags a
LEFT JOIN users_tag b
on a.ID = b.tagID
GROUP BY a.id, a.tagText
SQLFiddle Demo