This is my query:
SELECT usr.id,
count(DISTINCT sol.id) as 'Asked',
count(DISTINCT ans.id) as 'Answered',
sum(DISTINCT CASE ans.accepted WHEN 1 THEN 1 ELSE 0 end) as 'Accepted'
FROM tbl_users usr
LEFT JOIN tbl_solutions sol on sol.authorID = usr.id
LEFT JOIN tbl_solution_answers ans on ans.authorID = usr.id
group by usr.id, sol.authorID
My above query with the sum(DISTINCT CASE ans.accepted WHEN 1 THEN 1 ELSE 0 end) only ever returns 1 though I know that's not the case. I've tried adding a group clause on the ans.authorID but it has no effect.
How can I get the sum of all rows from the tbl_solution_answers ans table where the authorID is that of tbl_users.id and Accepted is 1.
SELECT usr.id,
count(DISTINCT sol.id) as 'Asked',
count(DISTINCT ans.id) as 'Answered',
count(DISTINCT case ans.accepted when 1 then ans.id end) as 'Accepted'
FROM tbl_users usr
LEFT JOIN tbl_solutions sol on sol.authorID = usr.id
LEFT JOIN tbl_solution_answers ans on ans.authorID = usr.id
group by usr.id, sol.authorID, ans.authorID
After so many permutations count(DISTINCT case ans.accepted when 1 then ans.id end) as 'Accepted' seems to work. Now if an authorID in tbl_solution_answers has 8 rows they'll all be returned as Answered and if say 3 of them are Accepted then 3 is returned as Accepted.
Related
Sorry for asking here this but I need help and google is not being nice.
I have the following table Products
SELECT
COUNT(CASE when core.kits.Location = core.suppliers.id THEN 1 END) as total,
COUNT(CASE when core.kits.cp = 1 THEN 1 END) as used,
core.suppliers.id, core.suppliers.name, core.suppliers.email,
core.suppliers.cperson, core.suppliers.adress, core.suppliers.phone
FROM core.kits
LEFT join core.suppliers on core.kits.Location = core.suppliers.id
WHERE core.suppliers.id is not null
AND banned=0
GROUP BY core.suppliers.id
ORDER BY name ASC
LIMIT 1000 OFFSET 0
but does not give me all the suppliers with zeros for the ones who have no appearance in kits.
Then in I do
SELECT
COUNT(CASE when core.kits.Location = core.suppliers.id THEN 1 END) as total,
COUNT(CASE when core.kits.cp = 1 THEN 1 END) as used,
core.suppliers.id, core.suppliers.name, core.suppliers.email,
core.suppliers.cperson, core.suppliers.adress, core.suppliers.phone
FROM core.suppliers
LEFT join core.suppliers on core.suppliers.id = core.kits.Location
WHERE core.suppliers.id is not null
AND banned=0
GROUP BY core.suppliers.id
ORDER BY name ASC
LIMIT 1000 OFFSET 0
I get all suppliers and correct numbers but the query takes 8 seconds instead of 1s. Any ideas how can I get all the suppliers with the count of stocks in 1s?
cheers.
If you want all the suppliers, even those that do not appear in kits you should do a LEFT join of suppliers to kits:
SELECT COUNT(k.Location) AS total,
COUNT(CASE WHEN k.cp = 1 THEN 1 END) AS used,
s.id, s.name, s.email, s.cperson, s.adress, s.phone
FROM core.suppliers s LEFT JOIN core.kits k
ON k.Location = s.id
WHERE banned=0
GROUP BY s.id
ORDER BY s.name ASC
LIMIT 1000 OFFSET 0;
I assume that core.suppliers.id is the primary key of suppliers, so that the conition:
core.suppliers.id is not null
is not needed.
Also, if the column banned is contained in the table kits, then the condition should be moved in the ON clause:
ON k.Location = s.id AND k.banned=0
and the WHERE clause should be removed.
In below query (Mentors) are 13 which shows me 26, while (SchoolSupervisor) are 5 which shows me 10 which is wrong. it is because of the Evidence which having 2 evidance, because of 2 evidence the Mentors & SchoolSupervisor values shows me double.
please help me out.
Query:
select t.c_id,t.province,t.district,t.cohort,t.duration,t.venue,t.v_date,t.review_level, t.activity,
SUM(CASE WHEN pr.p_association = "Mentor" THEN 1 ELSE 0 END) as Mentor,
SUM(CASE WHEN pr.p_association = "School Supervisor" THEN 1 ELSE 0 END) as SchoolSupervisor,
(CASE WHEN count(file_id) > 0 THEN "Yes" ELSE "No" END) as evidence
FROM review_m t , review_attndnce ra
LEFT JOIN participant_registration AS pr ON pr.p_id = ra.p_id
LEFT JOIN review_files AS rf ON rf.training_id = ra.c_id
WHERE 1=1 AND t.c_id = ra.c_id
group by t.c_id, ra.c_id order by t.c_id desc
enter image description here
You may perform the aggregations in a separate subquery, and then join to it:
SELECT
t.c_id,
t.province,
t.district,
t.cohort,
t.duration,
t.venue,
t.v_date,
t.review_level,
t.activity,
pr.Mentor,
pr.SchoolSupervisor,
rf.evidence
FROM review_m t
INNER JOIN review_attndnce ra
ON t.c_id = ra.c_id
LEFT JOIN
(
SELECT
p_id,
COUNT(CASE WHEN p_association = 'Mentor' THEN 1 END) AS Mentor,
COUNT(CASE WHEN p_association = 'School Supervisor' THEN 1 END) AS SchoolSupervisor,
FROM participant_registration
GROUP BY p_id
) pr
ON pr.p_id = ra.p_id
LEFT JOIN
(
SELECT
training_id,
CASE WHEN COUNT(file_id) > 0 THEN 'Yes' ELSE 'No' END AS evidence
FROM review_files
GROUP BY training_id
) rf
ON rf.training_id = ra.c_id
ORDER BY
t.c_id DESC;
Note that this also fixes another problem your query had, which was that you were selecting many columns which did not appear in the GROUP BY clause. Under this refactor, there is nothing wrong with your current select, because the aggregation take place in a separate subquery.
try adding this to the WHERE part of your query
AND pr.p_id IS NOT NULL AND rf.training_id IS NOT NULL
You can add a group by pr.p_id to remove the duplicate records there. Since, the group by on pr is not present as of now, there might be multiple records of same p_id for same ra
group by t.c_id, ra.c_id, pr.p_id order by t.c_id desc
I'm trying to COUNT attendance_status of drivers according to its value.
this is my code as of moment.
SELECT *, COUNT(attendance_status) AS total_cars_dispatched
FROM driver_attendance da
LEFT JOIN collectible co ON (da.driver_attendance_id=co.driver_attendance_id)
LEFT JOIN driver_pondo dp ON (dp.collectible_id=co.collectible_id)
WHERE attendance_status=19 AND company_id=84 GROUP BY attendance_date DESC
I'd like to know how to make another COUNT of attendance_status when it's value is 4 using a single query.
Try this:
SELECT attendance_date,
SUM(CASE WHEN attendance_status = 19 THEN 1 ELSE 0 END) AS total_cars_dispatched,
SUM(CASE WHEN attendance_status = 4 THEN 1 ELSE 0 END) AS attendance_status_4
FROM driver_attendance da
LEFT JOIN collectible co ON da.driver_attendance_id=co.driver_attendance_id
LEFT JOIN driver_pondo dp ON dp.collectible_id=co.collectible_id
WHERE company_id=84
GROUP BY attendance_date DESC;
So far I've got this:
SELECT connections.id,
connections.word_id,
connections.order_id,
connections.top,
connections.deleted,
(UNIX_TIMESTAMP() - UNIX_TIMESTAMP(connections.modified)) AS modified_ago,
words_en.word,
(CASE WHEN words_en.user_id = 1 THEN "You" ELSE words_en.user_id END) AS created_by
FROM connections, words_en
WHERE connections.word_id = words_en.id AND connections.user_id = 1
ORDER BY connections.order_id
I want to add few things, but I can't get syntax correct.
(CASE WHEN words_en.user_id = 1 THEN "You" ELSE words_en.user_id END) here, when ELSE, instead of ID i'd like to get name_surname column of this user from users table. So I need to do another join? But since it is within case, how would I do that?
connections.word_id from the SELECT. besides ID, I also want to know how many times this word_id is present in connections table. But excluding current user from the list.
I hope explanation was clear enough.
First, rewrite your query using ANSI joins, and add table aliases, like this:
SELECT c.id,
c.word_id,
c.order_id,
c.top,
c.deleted,
(UNIX_TIMESTAMP() - UNIX_TIMESTAMP(c.modified)) AS modified_ago,
words_en.word,
(CASE WHEN words_en.user_id = 1 THEN "You" ELSE w.user_id END) AS created_by
FROM connections c
JOIN words_en w ON c.word_id = w.id
WHERE c.user_id = 1
ORDER BY c.order_id
Now extending this query becomes easier: to bring in the user by w.user_id, add another join:
SELECT c.id,
c.word_id,
c.order_id,
c.top,
c.deleted,
(UNIX_TIMESTAMP() - UNIX_TIMESTAMP(c.modified)) AS modified_ago,
words_en.word,
(CASE WHEN words_en.user_id = 1 THEN "You" ELSE u. name_surname END) AS created_by
FROM connections c
JOIN words_en w ON c.word_id = w.id
JOIN users u ON w.user_id = u.id
WHERE c.user_id = 1
ORDER BY c.order_id
To add the count, use a subquery, like this:
SELECT c.id,
c.word_id,
c.order_id,
c.top,
c.deleted,
(UNIX_TIMESTAMP() - UNIX_TIMESTAMP(c.modified)) AS modified_ago,
words_en.word,
(CASE WHEN words_en.user_id = 1 THEN "You" ELSE u. name_surname END) AS created_by,
(
SELECT COUNT(*)
FROM connections cc
WHERE cc.word_id=c.word_id -- It's the same word
AND cc.user_id <> c.user_id -- user by a different user
) as uses_by_others
FROM connections c
JOIN words_en w ON c.word_id = w.id
JOIN users u ON w.user_id = u.id
WHERE c.user_id = 1
ORDER BY c.order_id
SELECT connections.id,
connections.word_id,
connections.order_id,
connections.top,
connections.deleted,
(UNIX_TIMESTAMP() - UNIX_TIMESTAMP(connections.modified)) AS modified_ago,
words_en.word,
(CASE WHEN words_en.user_id = 1 THEN "You" ELSE users.name_surname END) AS created_by
FROM connections JOIN words
WHERE connections.word_id = words_en.id AND connections.user_id = 1 JOIN users ON users.id=words_en.user_id
ORDER BY connections.order_id
I cant tell from your answer how to link the users table,post the tables schemas.Just a wild guess.
I have
users
------------------------
id | name | other_stuff.....
.
engagement
------------------------
user_id | type_code |
type_code is a varchar, but either A, B, C or NULL
[ EDIT for clarity: Users can have many engagements of each type code. SO I want to count how many they have of each. ]
I want to return ALL user rows, but with a count of A, B and C type engagements. E.g.
users_result
------------------------
user_id | user_name | other_stuff..... | count_A | count_B | count_C |
I've done quite a bit of searching, but found the following issues with other solutions:
The "other_stuff..." is actually grouped / concatenated results from a dozen other joins, so it's a bit of a monster already. So I need to be able to just add the additional fields to the pre-existing "SELECT ...... FROM users..." query.
The three additional required bits of data all come from the same engagement table, each with their own condition. I havent found anything to allow me to use the three conditions on the same related table.
Thanks
[edit]
I tried to simplify the question so people didn't have to look through loads of unnecessary stuff, but seems I might not have given enough info. Here is 'most' of the original query. I've taken out a lot of the selected fields as there are loads, but I've left most of the joins in so you can see basically what is actually going on.
SELECT
user.id,
user.first_name,
user.second_name,
GROUP_CONCAT(DISTINCT illness.id ORDER BY illness.id SEPARATOR ',' ) AS reason_for_treatment,
IF(ww_id=1000003, 1,'') as user_refused_program,
Group_CONCAT(DISTINCT physical_activity.name SEPARATOR ', ') AS programme_options,
COUNT(CASE WHEN engagement_item.type_code LIKE 'wm6%' THEN 1 ELSE NULL END) as count_A,
COUNT(CASE WHEN engagement_item.type_code LIKE 'wm12%' THEN 1 ELSE NULL END) as count_B,
COUNT(CASE WHEN engagement_item.type_code LIKE 'wm6%' THEN 1 ELSE NULL END) as count_C
FROM `user`
LEFT JOIN session AS session_induction ON (user.id = session_induction.user_id AND session_induction.session_type_id = 3)
LEFT JOIN stats AS stats_induction ON session_induction.id = stats_induction.session_id
LEFT JOIN session AS session_interim ON (user.id = session_interim.user_id AND session_interim.session_type_id = 4)
LEFT JOIN stats AS stats_interim ON session_interim.id = stats_interim.session_id
LEFT JOIN session AS session_final ON (user.id = session_final.user_id AND session_final.session_type_id = 5)
LEFT JOIN stats AS stats_final ON session_final.id = stats_final.session_id
LEFT JOIN user_has_illness ON user.ID = user_has_illness.user_id
LEFT JOIN illness ON user_has_illness.illness_id = illness.id
LEFT JOIN user_has_physical_activity ON user.ID = user_has_physical_activity.user_id
LEFT JOIN physical_activity ON user_has_physical_activity.physical_activity_id = physical_activity.id
LEFT JOIN engagement_item ON user.ID = engagement_item.user_ID
WHERE (user.INDUCTION_DATE>='2010-06-09' AND user.INDUCTION_DATE<='2011-06-09' AND user.archive!='1' )
GROUP BY user.id, engagement_item.user_id
It's worth mentioning that it works fine - returns all users with all details required. Except for the count_A B and C cols.
[edit added slightly more simplified query below]
Stripped out the unrelated joins and selects.
SELECT
user.id,
user.first_name,
COUNT(CASE WHEN engagement_item.type_code LIKE 'wm6%' THEN 1 ELSE NULL END) as count_A,
COUNT(CASE WHEN engagement_item.type_code LIKE 'wm12%' THEN 1 ELSE NULL END) as count_B,
COUNT(CASE WHEN engagement_item.type_code LIKE 'wm6%' THEN 1 ELSE NULL END) as count_C
FROM `user`
LEFT JOIN engagement_item ON user.ID = engagement_item.user_ID
GROUP BY user.id, engagement_item.user_id
SELECT e.user_id, u.name,
COUNT(CASE type_code WHEN 'A' THEN 1 ELSE NULL END) as count_A,
COUNT(CASE type_code WHEN 'B' THEN 1 ELSE NULL END) as count_B,
COUNT(CASE type_code WHEN 'C' THEN 1 ELSE NULL END) as count_C
FROM engagement e join users u on (e.user_id = u.id)
GROUP BY e.user_id, u.name
I would use COUNT instead of SUM just because that is what it is made for, counting things when not NULL.
SELECT
user.id,
user.first_name,
user.second_name,
GROUP_CONCAT(DISTINCT illness.id ORDER BY illness.id SEPARATOR ',' ) AS reason_for_treatment,
IF(ww_id=1000003, 1,'') as user_refused_program,
Group_CONCAT(DISTINCT physical_activity.name SEPARATOR ', ') AS programme_options,
ei.count_A, ei.count_B, ei.count_C
FROM `user`
LEFT JOIN ( SELECT user_id
, COUNT(CASE WHEN engagement_item.type_code LIKE 'wm6%' THEN 1 ELSE NULL END) as count_A
, COUNT(CASE WHEN engagement_item.type_code LIKE 'wm12%' THEN 1 ELSE NULL END) as count_B
, COUNT(CASE WHEN engagement_item.type_code LIKE 'wm6%' THEN 1 ELSE NULL END) as count_C
FROM engagement_item
GROUP BY userid ) ei
LEFT JOIN session AS session_induction ON (user.id = session_induction.user_id AND session_induction.session_type_id = 3)
LEFT JOIN stats AS stats_induction ON session_induction.id = stats_induction.session_id
LEFT JOIN session AS session_interim ON (user.id = session_interim.user_id AND session_interim.session_type_id = 4)
LEFT JOIN stats AS stats_interim ON session_interim.id = stats_interim.session_id
LEFT JOIN session AS session_final ON (user.id = session_final.user_id AND session_final.session_type_id = 5)
LEFT JOIN stats AS stats_final ON session_final.id = stats_final.session_id
LEFT JOIN user_has_illness ON user.ID = user_has_illness.user_id
LEFT JOIN illness ON user_has_illness.illness_id = illness.id
LEFT JOIN user_has_physical_activity ON user.ID = user_has_physical_activity.user_id
LEFT JOIN physical_activity ON user_has_physical_activity.physical_activity_id = physical_activity.id
LEFT JOIN engagement_item ON user.ID = engagement_item.user_ID
WHERE (user.INDUCTION_DATE>='2010-06-09' AND user.INDUCTION_DATE<='2011-06-09' AND user.archive!='1' )
GROUP BY user.id, engagement_item.user_id, ei.count_A, ei.count_B, ei.count_C
Something like this perhaps?
select e.user_id, u.name,
sum(case e.type_code when 'A' then 1 else 0 end) as count_A,
sum(case e.type_code when 'B' then 1 else 0 end) as count_B,
sum(case e.type_code when 'C' then 1 else 0 end) as count_C
from engagement e join users u on (e.user_id = u.id)
group by e.user_id, u.name
The interesting part is the use of CASE inside the SUM to split the counting into three chunks.