Aliased LEFT JOIN affects SUM unexpectedly - mysql

Why do the two queries below give different results? I thought that joins in the case like those below shouldn't interact with each other, but they apparently are.
The query:
SELECT
s.id,
SUM(CASE WHEN n.template_id = 1 THEN 1 ELSE 0 END) AS template_1
FROM schedulings AS s
LEFT JOIN notes AS calls_made
ON s.id = calls_made.schedule_id
AND calls_made.template_id IN (1, 2, 3, 5, 6, 9, 10, 11, 12, 14)
LEFT OUTER JOIN notes AS n
ON s.id = n.schedule_id
WHERE s.id = 48810;
The results:
id template_1
48810 70
However, if I change the query by commenting out (or removing) the first notes join, I get the expected result.
The query:
SELECT
s.id,
SUM(CASE WHEN n.template_id = 1 THEN 1 ELSE 0 END) AS template_1
FROM schedulings AS s
LEFT OUTER JOIN notes AS n
ON s.id = n.schedule_id
WHERE s.id = 48810;
The result:
id template_1
48810 7

Related

MySQL JOIN with count / distinct

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,

Display results in SQL that meet the criteria

select only those top 10 hospitals that have both kinds of ICU and SICU beds, i.e. only hospitals that have at least 1 ICU bed and at least 1 SICU bed can be included in this part of the analysis. Here is what I have so far
select bu.business_name as 'Hospital Name'
,sum(be.license_beds) as Total_Licenses
,case when be.bed_id = 4 then 'ICU' end as "ICU"
,case when be.bed_id = 15 then 'SICU' end as "SICU"
from bed_fact be
join bed_type bt
on be.bed_id = bt.bed_id
join business bu
on be.ims_org_id = bu.ims_org_id
where be.bed_id = 4
or be.bed_id = 15
and be.license_beds IS NOT NULL
group
by bu.business_name
order
by Total_Licenses DESC
limit 10
;
I need to some how only count the hospital that has at least one of ICU or SICU value
You want conditional aggregation and a having clause:
select
bu.business_name as Hospital_Name,
sum(be.license_beds) as Total_Licenses,
sum(be.bed_id = 4) as ICU,
sum(be.bed_id = 15) as SICU
from bed_fact be
inner join bed_type bt on be.bed_id = bt.bed_id
inner join business bu on be.ims_org_id = bu.ims_org_id
where be.bed_id in (4, 15) and be.license_beds is not null
group by bu.business_name
having ICU > 0 and SICU > 0
order by Total_Licenses desc
limit 10
If you don't what the counts in the resultset, then move the aggregate functions to the having clause:
select
bu.business_name as Hospital_Name,
sum(be.license_beds) as Total_Licenses
from bed_fact be
inner join bed_type bt on be.bed_id = bt.bed_id
inner join business bu on be.ims_org_id = bu.ims_org_id
where be.bed_id in (4, 15) and be.license_beds is not null
group by bu.business_name
having sum(be.bed_id = 4) > 0 and sum(be.bed_id = 15) > 0
order by Total_Licenses desc
limit 10

SQL - How can I use UNION to join three INNER JOIN results into a single results table?

For the table:
assistants_rating(
id INT PRIMARY KEY auto_increment,
assistant_id INT(11),
rating INT(1)
)
And another table of assistants which contains a name. My query goes as follows:
(SELECT assistants.name AS assist_name , count(rating) AS OneStar FROM assistants_rating
INNER JOIN assistants on assistants.assistant_id = assistants_rating.assistant_id WHERE rating = 1)
UNION
(SELECT assistants.name AS assist_name , count(rating) AS TwoStar FROM assistants_rating
INNER JOIN assistants on assistants.assistant_id = assistants_rating.assistant_id WHERE rating = 2)
UNION
(SELECT assistants.name AS assist_name , count(rating) AS ThreeStar FROM assistants_rating
INNER JOIN assistants on assistants.assistant_id = assistants_rating.assistant_id WHERE rating = 3)
GROUP BY assistants.name,OneStar,TwoStar,ThreeStar;
Let's say I have the assistants named Bob and Sophie, the query should return:
assist_name OneStar TwoStar ThreeStar
Bob 9 18 52
Sophie 15 8 61
But instead I'm getting a SQL syntax error, which is weird because when I do each of them alone , they work properly and that leads me to believe that my syntax is good. Not only that, but my queries with the UNION work if I only do TwoStar and ThreeStar together but not with OneStar and TwoStar.
I'm so confused; why doesn't this work?
UNION doesn't help here anyway. It does a different thing.
The query you need is something along the lines of:
SELECT
assistants.name AS assist_name,
SUM(IF(rating = 1, 1, 0)) AS OneStar,
SUM(IF(rating = 2, 1, 0)) AS TwoStar,
SUM(IF(rating = 3, 1, 0)) AS ThreeStar
FROM assistants_rating
INNER JOIN assistants ON assistants.assistant_id = assistants_rating.assistant_id
GROUP BY assistants.name
You can use CASE instead of Union
SELECT assistants.name AS assist_name,
SUM(CASE WHEN rating =1 THEN 1 ELSE 0 END) AS OneStar,
SUM(CASE WHEN rating =2 THEN 1 ELSE 0 END) AS TwoStar,
SUM(CASE WHEN rating =3 THEN 1 ELSE 0 END) AS ThreeStar
FROM assistants_rating
INNER JOIN assistants on assistants.assistant_id = assistants_rating.assistant_id
GROUP BY assistants.name

TSQL conditional join for values in second table

I want to do conditional join on two tables and wanted to join with highest status in the second table. The status values are Assigned, Booked, Delivery and Closed.
SELECT
CPC.CpcID, StatusFlow = CPC.Status, Orders.CarModel, EnquiryLog.EnquiryStatus
FROM
CPC
INNER JOIN
Orders ON CPC.CpcID = Orders.CpcID
INNER JOIN
EnquiryLog ON CPC.CpcID = EnquiryLog.CpcID
WHERE
CPC.CpcID = '24092015/12'
So in this case it should show only one row with EnquiryStatus 'Delivery' but based on my query the result is:
SQL query output:
If I got it the right way:
SELECT CPC.CpcID, StatusFlow = CPC.Status, Orders.CarModel, ca.EnquiryStatus
FROM CPC
INNER JOIN Orders ON CPC.CpcID = Orders.CpcID
CROSS APPLY(SELECT TOP 1 * FROM EnquiryLog WHERE CPC.CpcID = EnquiryLog.CpcID
ORDER BY CASE EnquiryStatus
WHEN 'CLOSED' THEN 1
WHEN 'DELIVERY' THEN 2
WHEN 'BOOKED' THEN 3
WHEN 'ASSIGNED' THEN 4 END) ca
WHERE CPC.CpcID='24092015/12'

Mysql::Error: Subquery returns more than 1 row:

In my rails app, I am running a sql query using find_by_sql() since I need subqueries.
This works if I do either the first or second query but when I add them together with the AND, it starts complaining about more than 1 row in subquery.
I want all rows (records) returned that match the criteria. What needs to be fixed/changes here? What is telling mysql I only want 1 row?
Here is the resultant SQL as viewed in the rails log:
Mysql::Error: Subquery returns more than 1 row: select p.* from policies p
where exists (select 0 from status_changes sc join statuses s on sc.status_id = s.id
where sc.policy_id = p.id
and s.status_category_id = '1'
and sc.created_at between '2009-03-10' and '2009-03-12')
or exists
(select 0 from status_changes sc join statuses s on sc.status_id = s.id
where sc.created_at in
(select max(sc2.created_at)
from status_changes sc2
where sc2.policy_id = p.id
and sc2.created_at < '2009-03-10')
and s.status_category_id = '1'
and sc.policy_id = p.id)
AND (select 0 from status_changes sc
where sc.policy_id = p.id
and sc.status_id = 7
and sc.created_at between '2008-12-31' and '2009-03-12')
or exists
(select 0 from status_changes sc
where sc.created_at in
(select max(sc2.created_at)
from status_changes sc2
where sc2.policy_id = p.id
and sc2.created_at < '2008-12-31')
and sc.status_id = 7
and sc.policy_id = p.id)
This line:
AND (select 0 from status_changes sc
Shouldn't it be
AND exists (select 0 from status_changes sc
Subqueries that return more than 1 row are not supported by any SQL server, as far as I am aware.