Multiple Counts from many INNER JOIN tables with Conditions - mysql

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

Related

Mysql join not showing all records

I am using Php with join, I have two tables ("services" and "service_detail"), I want to get all services
but want to know which service selected or notselected by vendor
Here is my services table strcture
id service_name image
1 Abc abc.jpg
2 xyz xyz.jpg
3 OPS ops.jpg
4 tys tys.jpg
5 byp byp.jpg
Here is my services_detail table strcutre
id vendor_id service_id price
1 101 1 50
2 101 2 70
3 101 3 80
4 101 4 30
5 102 1 70
6 102 2 40
...
I tried with following query but showing only selected services, but i want to get all services with parameter ( selected or notselected)
Where i am wrong ? Here is my query
SELECT sd.vendor_id, sd.service_id, sd.price, s.service_name, s.image
FROM services_detail sd
LEFT JOIN services s
ON sd.service_id = s.id
WHERE sd.vendor_id = '101'
Move your where clause to be AND in ON clause:
AND sd.vendor_id = '101'
And interchange tables in join to get all servcies
SELECT sd.vendor_id, sd.service_id, sd.price, s.service_name, s.image,
IF (sd.vendor_id is not null, 'Opted', 'Not opted') as status
FROM services s
LEFT JOIN services_detail sd
ON sd.service_id = s.id AND sd.vendor_id = '101';
In simple words, when there is a where clause including filters on table of Left Join then it will act like INNER JOIN not LEFT JOIN.

MySQL count without grouping

I am running the following query to understand to get users' first attempt to answer a question listed next to their second attempt.
SELECT
s.id AS attempt_id_first, m.id AS attempt_id_second, s.user_id
FROM
attempt s
INNER JOIN attempt m on s.user_id = m.user_id
WHERE
s.id<m.id
I end up with this:
attempt_first attempt_second user_id
7 17 1
9 10 2
9 15 2
10 15 2
4 6 9
24 25 15
29 34 19
29 36 19
34 36 19
I would like to have a new column that counts the number of attempts by users so that:
7 17 1 1
9 10 2 3
9 15 2 3
10 15 2 3
4 6 9 1
24 25 15 1
29 34 19 3
29 36 19 3
34 36 19 3
I am sure this is trivial, but I cannot get it to work. Help anyone?
I think this is it: Just display the results, and throw in an extra count subquery:
select
userid,
id,
(select
count('x')
from
attempt x
where
x.userid = a.userid) as attempcount
from
attempt a
If you like to keep the first and second attempt in separate columns, you can of course embed the subselect in your original query.
It seems wrong, though. Firstly, you need to have at least two attemps, otherwise none will show. You can solve that by changing inner join to left join and move the condition in the where clause to that join. Secondly, the 'second attempt' is not the second attempt per say. Actually, for each of the attempts you get all next attempts. Look at the example of user 2. You accidentally get three rows (where there are three attemps), but you get attempt 9 and 10, as well as attempt 9 and 15 as well as 10 and 15. 9, 15 is incorrect, since 15 isn't the attempt that followed 9. The more attempts a user has, the more of these false results you will get.
If you want one attempt listed next to the next one, with the count, I would suggest:
SELECT s.user_id, s.id AS attempt_id_first,
(select s2.id
from attempt s2
where s2.user_id = s.user_id and
s2.id > s.id
order by s2.id
limit 1
) as attempt_id_second,
(select count(*)
from attempt s3
where s3.user_id = s.user_id
) as totalAttempts
FROM attempt s ;
This only lists each attempt once with the next one. The count is included as the last column.

MySQL - Multiple Conditions and Their Results with GROUP BY

table name : users u
id username src
1 mark 101
2 stanley 102
3 john 103
4 stewe 104
table name : call_history c
id src dst duration
1 101 555-1217 20
2 555-1315 102 30
3 555-2245 102 40
4 102 555-6523 30
5 102 555-4213 20
6 555-1689 102 15
7 103 555-1775 35
There are two tables and these columns.
Conditions are;
SUM(duration) AS OutboundSUM (Condition: u.src=c.src )
COUNT(duration) AS OutboundCNT (Condition: u.src=c.src )
SUM(duration) AS InboundSUM (Condition: u.src=c.dst )
COUNT(duration) AS InboundCNT (Condition: u.src=c.dst )
What I need to see with Group By per username;
username OutboundSUM OutboundCNT InboundSUM InboundCNT
mark 20 1 0 0
stanley 50 2 85 3
john 35 1 0 0
stewe 0 0 0 0
I tried UNION ALL, sub query after select, INNER JOIN but It didn't work.
Union gives me 2 line for each username, join makes me crazy, sub queries takes longtime and wrong results.
All help is appreciated.
Problem, solved with Kicstart's solution. Thank you very much for each help.
Can you provide the primary keys of the table? It would help us give better answers.
Also, you MUST include both conditions u.src=c.src AND u.id=c.id for join.
If the IDs of the two tables do not relate to each other, I suggest you use different attribute names.
Couple of sub queries?
SELECT a.src,
oBSum AS OutboundSUM,
oBCnt AS OutboundCNT,
iBSum AS InboundSUM,
iBCnt AS InboundCNT
FROM users u
LEFT OUTER JOIN (SELECT src, SUM(duration) AS oBSum, COUNT(*) AS oBCnt FROM call_history GROUP BY src) ob
ON u.src = ob.src
LEFT OUTER JOIN (SELECT dst, SUM(duration) AS iBSum, COUNT(*) AS iBCnt FROM call_history GROUP BY dst) ib
ON u.src = ib.dst

MySQL: Another max per group? Two tables

My database tracks sections users have completed:
Table 'users':
id user_id sections_id
//
4 46 1
5 46 2
6 46 4
7 46 5
//
Table 'sections':
id header_id name
1 1 1/3
2 1 2/3
3 1 3/3
4 2 1/3
5 2 2/3
6 2 3/3
The following query
SELECT a.sections_id
,b.header_id
FROM users a
JOIN sections b
ON a.sections_id = b.id
WHERE a.user_id = 46;
// a.user_id can be just user_id, but added for clarity
Gives me:
sections_id header_id
1 1
2 1
4 2
5 2
What I want is max section ID per header for a particular user, so that I know which section I need to serve the user:
sections_id header_id
2 1
5 2
I'm assuming this is a max per group problem, but I can't quite get my head around the solution. I could throw all the data into my PHP and parse out from there, but it seems I should be able to do it via the SQL. TIA!
This is a simple group by query:
SELECT s.header_id, max(u.sections_id)
FROM users u JOIN
sections s
ON u.sections_id = s.id
WHERE u.user_id = 46
group by s.header_id;
I also changed your aliases to be the initials of the table. This makes the query much easier to follow.
Edit: SQLFiddle Here: http://sqlfiddle.com/#!2/dbb5a/2
You could add a group by clause with a max() function
SELECT max(a.sections_id)
,b.header_id
FROM users a
JOIN sections b
ON a.sections_id = b.id
WHERE a.user_id = 46
GROUP BY header_id;

SQL Sorting with Two Joined Tables

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