MySQL JOIN with count / distinct - mysql

I've got multiple tables in my database.
Below is my SQL. It all works well for the majority.
How my system works is I may have a game which may sit in multiple competitions therefore will get called into this query more than once through the various JOINS.
It's like Liverpool playing a game but that game earns points for two competitions. It's not two games even though it'll appear twice. It's also not two rows in my database table 'game'.
What I have works for everything but the games that are in two competitions and where I want to do a few counts.
So my query code at the bottom works, but if I try add in
SUM(CASE WHEN g.isRanfurly = 1 THEN 1 ELSE 0 END) as TTLTests,
then this fails as it counts those games twice.
Any ideas?
SELECT DISTINCT(g.gameId), gd.playerId, t.teamName,
COUNT(distinct gd.gameId) as Appearances,
SUM(gd.tries) as TTLTries,
COUNT(CASE WHEN g.isTestMatch = 1 THEN 1 ELSE 0 END) as TTLTests,
IF(gd.homeaway = 1, g.team1Id, g.team2Id) as myteamId
FROM `gamedata` gd
JOIN `games` g ON gd.gameId = g.gameId
JOIN `teams` t ON t.teamId = IF(gd.homeaway = 1, g.team1Id, g.team2Id)
JOIN `roundgames` rg ON rg.gameId = gd.gameId
JOIN `rounds` r ON r.roundId = rg.roundId
JOIN `competitions` c ON r.competitionId = c.competitionId
WHERE `playerId` = 1 AND `didntPlay` = 0 AND t.teamType = 2
group by t.teamName

You can try the below - remove the else 0 from the conditional count
SELECT gd.playerId, t.teamName,
COUNT(distinct gd.gameId) as Appearances,
SUM(gd.tries) as TTLTries,
COUNT(CASE WHEN g.isTestMatch = 1 THEN 1 END) as TTLTests,
IF(gd.homeaway = 1, g.team1Id, g.team2Id) as myteamId
FROM `gamedata` gd
JOIN `games` g ON gd.gameId = g.gameId
JOIN `teams` t ON t.teamId = IF(gd.homeaway = 1, g.team1Id, g.team2Id)
JOIN `roundgames` rg ON rg.gameId = gd.gameId
JOIN `rounds` r ON r.roundId = rg.roundId
JOIN `competitions` c ON r.competitionId = c.competitionId
WHERE `playerId` = 1 AND `didntPlay` = 0 AND t.teamType = 2
group by gd.playerId, t.teamName

The solution was to use DISTINCT within the SUM
SUM(CASE WHEN g.isTestMatch = 1 THEN gd.tries ELSE 0 END) as TTLTestTries,

Related

How to avoid repetitions of columns in MySQL subquery?

i am retrieving the result from above 4 table using following query
SELECT
(SELECT SUM(CASE when c.Training_Id=1 then 1 else 0 end)
FROM courses c
INNER JOIN enrolled_students es
ON c.Course_Id = es.Course_Id
) STEM,
(SELECT SUM(CASE when c.Training_Id=2 then 1 else 0 end)
FROM courses c
INNER JOIN enrolled_students es ON c.Course_Id = es.Course_Id
) MA,
c.* FROM campus c;
The problem with this query is, two(2) students are in STEM and one(1) Student in MA against Campus_Id 3, but its repeating records against all campuses. i want if campus has no students than there should be '0' Zero.
You need to filter your subselects by Campus_Id. But first you have to use distinct table aliases. Change your last line to ca.* FROM campus ca. Then you can use a where clause in your subselects (WHERE c.Campus_Id = ca.Campus_Id).
SELECT
(SELECT SUM(CASE when c.Training_Id=1 then 1 else 0 end)
FROM courses c
INNER JOIN enrolled_students es
ON c.Course_Id = es.Course_Id
WHERE c.Campus_Id = ca.Campus_Id -- line added
) STEM,
(SELECT SUM(CASE when c.Training_Id=2 then 1 else 0 end)
FROM courses c
INNER JOIN enrolled_students es ON c.Course_Id = es.Course_Id
WHERE c.Campus_Id = ca.Campus_Id -- line added
) MA,
ca.* FROM campus ca; -- line changed
This should solve your problem.
To improve the performance you can also filter your subselects by Training_Id. In the first subselect you only need the rows with Training_Id=1. So you can change your where clause to:
WHERE c.Campus_Id = ca.Campus_Id
AND c.Training_Id = 1
Doing that you can also use COUNT instead of SUM. So your subselect would look like:
SELECT COUNT(1)
FROM courses c
INNER JOIN enrolled_students es ON c.Course_Id = es.Course_Id
WHERE c.Campus_Id = ca.Campus_Id AND c.Training_Id = 1
To prevent code duplication (your subselects are almost equal) you can join all needed tables and group by Campus_Id:
select
COUNT(co.Training_Id=1 OR NULL) STEM,
COUNT(co.Training_Id=2 OR NULL) MA,
ca.Campus_Id
from campus ca
left join courses co on co.Campus_Id = ca.Campus_Id
left join enrolled_students es on es.Course_Id = co.Course_Id
where co.Training_Id in (1, 2)
group by ca.Campus_Id

Split multiple count using in mysql with same table

I have a query in below format:
SELECT ETM.etm_Taxonomy, COUNT( PE.pp_profileID ) AS total_counts
FROM expertise_taxonomymaster AS ETM
LEFT JOIN expertise_taxonomy AS ET ON ETM.etm_ID = ET.`et_Taxonomy`
LEFT JOIN expertise AS E ON E.et_Taxonomy = ET.`et_ID`
LEFT JOIN profile_expertise AS PE ON PE.pp_expertiseID = E.et_ID
WHERE PE.pp_profileID IN (
SELECT PJ.pj_profileID
FROM jobtitle_taxonomymaster AS JTM
LEFT JOIN jobtitle_taxonomy AS JT ON JTM.jtm_ID = JT.`jt_Taxonomy`
LEFT JOIN jobtitle AS J ON J.jt_taxonomy = JT.`jt_ID`
LEFT JOIN profile_jobtitle AS PJ ON PJ.pj_jobtitleID = J.jt_ID
WHERE JTM.jtm_Taxonomy = 'Associate'
OR JTM.jtm_Taxonomy = 'Partner'
)
AND et_lawfirmID in (195,196)
GROUP BY etm_Taxonomy
And I have results as follows:
etm_Taxonomy total_counts
Advertising 18
Antitrust 47
Banking 258
But I need below results, Count should be split based on the JTM.ttm_Taxonomy field
etm_Taxonomy Patners195 Partners196 Associates195 Associates196
Advertising 18 18 18 18
Antitrust 47 47 47 47
Banking 258 258 258 258
Try this way:
SELECT ETM.etm_Taxonomy,
SUM (CASE WHEN PJ_TAX.jtm_Taxonomy = 'Associate' THEN 1 ELSE 0 END) AS Associates,
SUM (CASE WHEN PJ_TAX.jtm_Taxonomy = 'Partner' THEN 1 ELSE 0 END) AS Partners,
SUM (CASE WHEN PJ_TAX.jtm_Taxonomy = 'Consultant' THEN 1 ELSE 0 END) AS Consultants,
SUM (CASE WHEN PJ_TAX.jtm_Taxonomy = 'Counsel' THEN 1 ELSE 0 END) AS Counsels,
COUNT(PE.pp_profileID ) AS total_counts
FROM expertise_taxonomymaster AS ETM
LEFT JOIN expertise_taxonomy AS ET ON ETM.etm_ID = ET.`et_Taxonomy`
LEFT JOIN expertise AS E ON E.et_Taxonomy = ET.`et_ID`
LEFT JOIN profile_expertise AS PE ON PE.pp_expertiseID = E.et_ID
INNER JOIN
(
SELECT DISTINCT PJ.pj_profileID,JTM.jtm_Taxonomy
FROM jobtitle_taxonomymaster AS JTM
LEFT JOIN jobtitle_taxonomy AS JT ON JTM.jtm_ID = JT.`jt_Taxonomy`
LEFT JOIN jobtitle AS J ON J.jt_taxonomy = JT.`jt_ID`
LEFT JOIN profile_jobtitle AS PJ ON PJ.pj_jobtitleID = J.jt_ID
WHERE JTM.jtm_Taxonomy = 'Associate'
OR JTM.jtm_Taxonomy = 'Partner'
OR JTM.jtm_Taxonomy = 'Consultant'
OR JTM.jtm_Taxonomy = 'Counsel'
) as PJ_TAX
ON PE.pp_profileID= PJ_TAX.pj_profileID
WHERE et_lawfirmID =195
GROUP BY etm_Taxonomy
First of all: Your left outer joins are no outer joins really, because in your WHERE clause you say you want certain ETs and PEs only.
Mainly you want to join everything, then see whether partner or associate and whether 195 or 196 and count accordingly. This can be done with a CASE construct inside COUNT. Only problem may be duplicates leading to incorrect counts. Im am not completely sure about your database structure. In case there can be duplicate profileIDs with your inner query, you need a derived query with distinct, rather than just joining everything directly. Check if this works for you:
select
etm.etm_taxonomy,
count(case when t.jtm_taxonomy = 'Partner' and et_lawfirmid = 195 then 1 end) as patners195,
count(case when t.jtm_taxonomy = 'Partner' and et_lawfirmid = 196 then 1 end) as patners196,
count(case when t.jtm_taxonomy = 'Associate' and et_lawfirmid = 195 then 1 end) as associates195,
count(case when t.jtm_taxonomy = 'Associate' and et_lawfirmid = 196 then 1 end) as associates196
from expertise_taxonomymaster as etm
join expertise_taxonomy as et on etm.etm_id = et.et_taxonomy
join expertise as e on e.et_taxonomy = et.et_id
join profile_expertise as pe on pe.pp_expertiseid = e.et_id
join
(
select distinct pj.pj_profileid, jtm.jtm_taxonomy
from jobtitle_taxonomymaster as jtm
join jobtitle_taxonomy as jt on jtm.jtm_id = jt.jt_taxonomy
join jobtitle as j on j.jt_taxonomy = jt.jt_id
join profile_jobtitle as pj on pj.pj_jobtitleid = j.jt_id
where jtm.jtm_taxonomy in ('Associate', 'Partner')
) as t on t.pj_profileid = pe.pp_profileid
where et.et_lawfirmid in (195,196);
group by etm.etm_taxonomy;

(My)SQL JOIN - get teams with exactly specified members

Assume tables
team: id, title
team_user: id_team, id_user
I'd like to select teams with just and only specified members. In this example I want team(s) where the only users are those with id 1 and 5, noone else. I came up with this SQL, but it seems to be a little overkill for such simple task.
SELECT team.*, COUNT(`team_user`.id_user) AS cnt
FROM `team`
JOIN `team_user` user0 ON `user0`.id_team = `team`.id AND `user0`.id_user = 1
JOIN `team_user` user1 ON `user1`.id_team = `team`.id AND `user1`.id_user = 5
JOIN `team_user` ON `team_user`.id_team = `team`.id
GROUP BY `team`.id
HAVING cnt = 2
EDIT: Thank you all for your help. If you want to actually try your ideas, you can use example database structure and data found here: http://down.lipe.cz/team_members.sql
How about
SELECT *
FROM team t
JOIN team_user tu ON (tu.id_team = t.id)
GROUP BY t.id
HAVING (SUM(tu.id_user IN (1,5)) = 2) AND (SUM(tu.id_user NOT IN (1,5)) = 0)
I'm assuming a unique index on team_user(id_team, id_user).
You can use
SELECT
DISTINCT id,
COUNT(tu.id_user) as cnt
FROM
team t
JOIN team_user tu ON ( tu.id_team = t.id )
GROUP BY
t.id
HAVING
count(tu.user_id) = count( CASE WHEN tu.user_id = 1 or tu.user_id = 5 THEN 1 ELSE 0 END )
AND cnt = 2
Not sure why you'd need the cnt = 2 condition, the query would get only those teams where all of users having the ID of either 1 or 5
Try This
SELECT team.*, COUNT(`team_user`.id_user) AS cnt FROM `team`
JOIN `team_user` ON `team_user`.id_team = `team`.id
where `team_user`.id_user IN (1,5)
GROUP BY `team`.id
HAVING cnt = 2

mysql count occurrence of a string

I need to count how many times a couple categories appear in a column. They're storred as strings like Sports, Medicine, the column name is ct.category_name.
This is the query i'm adapting. I'd like a column for every category type.
select co.order_id, co.catalog_item_id, ct.category_name
from customer_order as co
join item_category as ic on (ic.item_id = co.customer_id )
join category_translations as ct on (ct.category_id = ic.category_id)
where co.paid = 1 and co.customer_id = 22500 and ct.locale = "en"
When I put this in the select statement it counts everything, I can see why, but I'm not sure which direction to go.
count(CASE
WHEN ct.category_name = "sports" THEN ct.category_name
ELSE 0
end) AS 'sports'
Again, i'd like the count for each string to be its own column. Any help would be much appreciated.
When I try:
select co.order_id, co.catalog_item_id, ct.category_name
, SUM(ct.category_name = "sports") AS `sports`
, SUM(ct.category_name = "medici") AS `medicine`
from customer_order as co
join item_category as ic on (ic.item_id = co.customer_id )
join category_translations as ct on (ct.category_id = ic.category_id)
where co.paid = 1 and co.customer_id = 22500 and ct.locale = "en"
It counts sports twice. Wrong place for the when? Results:
`23115 271708 sports 483 483`
It counts everything because COUNT increments its value for every not null value, and 0 is not NULL.
Possible solutions:
Replace 0 with NULL OR
Use SUM instead of COUNT:
SUM(CASE
WHEN ct.category_name = "sports" THEN 1
ELSE 0
end) AS 'sports'
or even
SUM(ct.category_name = "sports") AS `sports`

MySQL Row Output Cells into Columns

My question is how do you get row cell output into separate columns to make viewing that data more readable.
I have the following SQL Query:
SELECT TD.name AS Conditions, PV.value AS Frequency, MSL.name AS
Mailing_List_Subscriptions, Count(CI.uid) AS Users_Signup_Count
FROM conditions_interest CI
INNER JOIN profile_values PV
ON CI.uid = PV.uid
INNER JOIN hwmailservice_user_lists MSUL
ON CI.uid = MSUL.uid
INNER JOIN hwmailservice_lists MSL
ON MSUL.list_id = MSL.list_id
INNER JOIN term_data TD
ON CI.tid = TD.tid
WHERE (PV.value = 'daily' OR PV.value = 'weekly') AND CI.email = '1'
GROUP BY PV.value, TD.name, MSL.name
ORDER BY TD.name;
With the following output:
So all the mailing list subscriptions would have there own separate column with the counts associated with the conditions. So like this:
Conditions Frequency Newsletter Partners Annoucements marketing
Abscessed Tooth Daily 95 91 98 98
Abscessed Tooth Weekly 6 4 7 7
If more clarification is needed I will edit my post.
MySQL does not have a PIVOT function which is what you are doing, so you will want to use a CASE:
SELECT x.Conditions,
x.Frequency,
SUM(CASE WHEN Mailing_List_Subscriptions = 'newsletter' THEN Users_Signup_Count END) newsletter,
SUM(CASE WHEN Mailing_List_Subscriptions = 'partners' THEN Users_Signup_Count END) partners,
SUM(CASE WHEN Mailing_List_Subscriptions = 'announcements' THEN Users_Signup_Count END) announcements,
SUM(CASE WHEN Mailing_List_Subscriptions = 'marketing' THEN Users_Signup_Count END) marketing
FROM
(
SELECT TD.name AS Conditions, PV.value AS Frequency,
MSL.name AS Mailing_List_Subscriptions,
Count(CI.uid) AS Users_Signup_Count
FROM conditions_interest CI
INNER JOIN profile_values PV
ON CI.uid = PV.uid
INNER JOIN hwmailservice_user_lists MSUL
ON CI.uid = MSUL.uid
INNER JOIN hwmailservice_lists MSL
ON MSUL.list_id = MSL.list_id
INNER JOIN term_data TD
ON CI.tid = TD.tid
WHERE (PV.value = 'daily' OR PV.value = 'weekly') AND CI.email = '1'
GROUP BY PV.value, TD.name, MSL.name
) x
GROUP BY x.Conditions, x.Frequency
ORDER BY x.name