I am trying to filter results based on the name assigned on count() and get this:
Unknown column 'total_submissions' in 'where clause'
SELECT SQL_CALC_FOUND_ROWS patient.*,count(patient_data.id) as total_submissions
FROM patient
LEFT JOIN patient_data ON (patient_data.patient_id = patient.id AND patient_data.date_finished IS NOT NULL)
WHERE patient.doc_id = 2 AND total_submissions = 5
GROUP BY patient.id
ORDER BY patient.id DESC
LIMIT 0,40
After more research I did find out about not being able to use a column alias in the WHERE but I am unsure how to execute this query then. I assume it's possible but how would I be able to filter the results based on the count() calculation of the query?
total_submissions is a column alias and the result of an aggregation function. You need to do that check in a havingclause:
SELECT SQL_CALC_FOUND_ROWS p.*, count(pd.id) as total_submissions
FROM patient p LEFT JOIN
patient_data pd
ON pd.patient_id = p.id AND pd.date_finished IS NOT NULL
WHERE p.doc_id = 2
GROUP BY p.id
HAVING total_submissions = 5
ORDER BY p.id DESC
LIMIT 0, 40;
Notes:
Table aliases make the query easier to write and to read.
The condition on doc_id should still be in the WHERE clause.
You can't use column alias in where clause because the precedence in sql evaluation don't let the db engine know the alias name when evaluate the where clause
First is evaluated the FROM clase then the WHERE clause and after the SELECT cluase ..
In your case you have an aggregation function related to yu alias and this can be evaluated only after the group by is performed, pratically at the end of query process
for this reason there is a proper filter based on HAVING that work on the result of the aggreated query
SELECT SQL_CALC_FOUND_ROWS patient.*, count(patient_data.id) as total_submissions
FROM patient
LEFT JOIN patient_data ON (patient_data.patient_id = patient.id AND patient_data.date_finished IS NOT NULL)
WHERE patient.doc_id = 2
GROUP BY patient.id
HAVING total_submissions = 0
ORDER BY patient.id DESC
LIMIT 0,40
Related
I want to add a WHERE clause to my SQL query. but if I add AND n! = 1, I get an error.
how do I proceed?
thank you
SELECT
COUNT(1) AS n,
`prescription`.`id_prescription`
FROM
`intervention`
LEFT JOIN
`prescription`
ON
`prescription`.`id_prescription` = `intervention`.`id_prescription`
WHERE
`intervention`.`status` != "finish" AND `intervention`.`status` != "canceled"
GROUP BY
id_prescription
ORDER BY `n` DESC
Erreur
Requête SQL : Documentation
SELECT
COUNT(1) AS n,
`prescription`.`id_prescription`
FROM
`intervention`
LEFT JOIN
`prescription`
ON
`prescription`.`id_prescription` = `intervention`.`id_prescription`
WHERE
`intervention`.`status` != "finish" AND `intervention`.`status` != "canceled" AND `n` !=1
GROUP BY
id_prescription
ORDER BY `n`
DESC LIMIT 0, 25
MySQL a répondu: Documentation
#1054 - Champ 'n' inconnu dans where clause
Use having to filter on aggregates:
SELECT COUNT(*) AS n, id_prescription
FROM intervention i
LEFT JOIN prescription p USING(`id_prescription`)
WHERE i.status <> 'finish' AND i.status <> 'canceled'
GROUP BY id_prescription
HAVING COUNT(*) <> 1
ORDER BY n DESC
Side notes:
table aliases make the query easier to write and read
USING() comes handy to shorten the join syntax when the matching column(s) are homonyms
backticks are probably not necessary here
<> is the standard operator for inequality
single quotes are the standard quoting character for literal strings
MySQL extends the SQL standard and allows using column aliases in the HAVING clause, so you could also phrase it: HAVING n <> 1
It seems very strange that you are aggregating by the second table in a LEFT JOIN. If you want to count the number of interventions for each prescription, then your query should look like this:
SELECT p.id_prescription, COUNT(i.id_prescription) as num_interventions
FROM prescription p
intervention i
ON p.id_prescription = i.id_prescription AND
i.stqatus NOT IN ('finish', 'canceled')
GROUP BY p.id_prescription
HAVING COUNT(i.id_prescription) <> 1
ORDER BY COUNT(i.id_prescription) DESC;
This version of the query correctly returns 0 for the count when there are no interventions. I suspect that the HAVING clause you really want is:
HAVING COUNT(i.id_prescription) > 1
And if this interpretation is correctly, then an INNER JOIN is a better option than a LEFT JOIN, because the logic requires a match.
Tring the following query but i get; Error Code: 1055. Expression #3 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'PDC.PLG.LogDateTime' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by
I know that this is because of only full group by mode; how can I refactor this sort of query?
SELECT
SUM(PLG.Qty) AS TotQty,
SUM(PLG.ScrapQty) AS ScrpQty,
(
SELECT SUM(PLL.Qty)
FROM ProductionLog AS PLL
INNER JOIN ProductionPlan PPP ON PPP.PlanId = PLL.PlanId
WHERE
DATE(LogDateTime) = DATE(PLG.LogDateTime) AND
LogType = 8 AND
PPP.StationId = PP.StationId
) AS RwrkQty,
DATE(PLG.LogDateTime) AS LogDate,
S.StationName
FROM ProductionLog AS PLG
INNER JOIN ProductionPlan AS PP ON PLG.PlanId = PP.PlanId
INNER JOIN Station AS S ON S.StationId = PP.StationId
WHERE PLG.Logtype IN (4)
GROUP BY S.StationId,DATE(PLG.LogDateTime)
First, a proper query using a GROUP By means whatever the result fields you are trying to return, your GROUP by should include ALL fields that do not have any aggregation applied (min, max, sum, avg, etc.) So what is missing is that an extra column is in the list that is not aggregated, but also not part of the group by. So either add this non-aggregate field to the group by (even if the last field in group by), OR apply some aggregation to it.
Now, a cleanup for readability of your original query for readability of what is where and/or subquery of the next.
SELECT
SUM(PLG.Qty) AS TotQty,
SUM(PLG.ScrapQty) AS ScrpQty,
( SELECT SUM(PLL.Qty)
FROM ProductionLog AS PLL
INNER JOIN ProductionPlan PPP
ON PPP.PlanId = PLL.PlanId
WHERE
DATE(LogDateTime) = DATE(PLG.LogDateTime)
AND LogType = 8
AND PPP.StationId = PP.StationId ) AS RwrkQty,
DATE(PLG.LogDateTime) AS LogDate,
S.StationName
FROM
ProductionLog AS PLG
INNER JOIN ProductionPlan AS PP
ON PLG.PlanId = PP.PlanId
INNER JOIN Station AS S
ON S.StationId = PP.StationId
WHERE
PLG.Logtype IN (4)
GROUP BY
S.StationId,
DATE(PLG.LogDateTime)
In your scenario, your 3rd column which is based on a query has already been aggregated INSIDE it, but for respect to the OUTER query, it is NOT aggregated. To simplify this, just wrap IT in a MIN() such as
MIN( ( SELECT SUM(PLL.Qty)
FROM ProductionLog AS PLL
INNER JOIN ProductionPlan PPP
ON PPP.PlanId = PLL.PlanId
WHERE
DATE(LogDateTime) = DATE(PLG.LogDateTime)
AND LogType = 8
AND PPP.StationId = PP.StationId ) ) AS RwrkQty,
Since the inner query is only ever returning 1 row, summing 1 row will return the same value anyhow.
I'm trying to pass a column from the outer query as shown below to the inner query in the WHERE clause and MySQL does not like it. I'm unsure how to rewrite this query to make it work.
The error message I am getting is Unknown column 'y.DateShipped' in where clause
What I am trying to do is to join to the row in the inner table with an EffectiveDate that is less than the DateShipped and also is the max EffectiveDate in the inner join (there can be multiple rows for the same group by with different EffectiveDate(s))
I would love to know how to get this working or rewrite it so that it will work. I am using MySQL 5.6, so I don't have window functions available otherwise I think that could work.
select
x.id,
y.id,
y.DateShipped
from Shipment y inner join
(select id, SourceId, DestinationId, SourcePPFContractId, EffectiveDate
from Relationship where EffectiveDate <= y.DateShipped order by
EffectiveDate desc limit 1) x
on x.DestinationId = y.DestinationCustomerId
and x.SourceId = y.OriginCustomerId
and x.SourcePPFContractId = y.OriginContractId;
The inner select (from Relationship) is executed first and then merged with the first select. That's why it doesn't work. You should move the DateShipped to the where clause of the first select:
select
x.id,
y.id,
y.DateShipped
from Shipment y inner join
(select id, SourceId, DestinationId, SourcePPFContractId, EffectiveDate
from Relationship order by
EffectiveDate desc limit 1) x
on x.DestinationId = y.DestinationCustomerId
and x.SourceId = y.OriginCustomerId
and x.SourcePPFContractId = y.OriginContractId
and x.EffectiveDate <= y.DateShipped;
You are attempting something called a lateral join -- and MySQL does not support those. Because you want only one column, you can use a correlated subquery:
select (select r.id
from Relationship r
where r.DestinationId = s.DestinationCustomerId and
r.SourceId = s.OriginCustomerId and
r.SourcePPFContractId = s.OriginContractId and
r.EffectiveDate <= s.DateShipped
order by r.EffectiveDate desc
limit 1
) as x_id,
s.id, s.DateShipped
from Shipment s ;
Note that I also changed the table aliases to be abbreviations for the table names -- so the query is easier to read.
you would need to list the shipment table in the sub query to be able to call it properly try:
select
x.id,
y.id,
y.DateShipped
from Shipment y inner join
(select id, SourceId, DestinationId, SourcePPFContractId, EffectiveDate
from Relationship, Shipment where EffectiveDate <= Shipment.DateShipped order by
EffectiveDate desc limit 1) x
on x.DestinationId = y.DestinationCustomerId
and x.SourceId = y.OriginCustomerId
and x.SourcePPFContractId = y.OriginContractId;
What I am trying to do it with below code, getting all keywords with their positions via LEFT JOIN, it works fine but it shows the first position of each keyword, but I want to show the last position that recorded (by date).
SELECT keyword.id, keyword.title, keyword.date, rank.position FROM keyword
LEFT JOIN rank
ON rank.wordid = keyword.id
GROUP BY keyword.id
ORDER BY keyword.date DESC
How can I do this? Should I use subquery or what? Is there any way to do this without a subquery?
SAMPLE DATA
What I want:
Get 17 instead of 13, I mean last record of position.
Do not use group by for this! You want to filter, so use a where clause. In this case, using a correlated subquery works well:
SELECT k.id, k.title, k.date, r.position
FROM keyword k LEFT JOIN
rank r
ON r.wordid = k.id AND
r.date = (SELECT MAX(r2.date)
FROM rank r2
WHERE r2.wordid = k.id
)
ORDER BY k.date DESC
You can use below query
SELECT keyword.id, keyword.title, keyword.date, rankNew.position FROM keyword LEFT JOIN (
SELECT rank.wordid, rank.position FROM rank ORDER BY rank.id DESC LIMIT 0, 1) AS rankNew ON (rankNew.wordid = keyword.id);
You can get more reference from Retrieving the last record in each group - MySQL
Im am trying to create a query that joins on some data for each row of the main query, but I do not know how to get around the issue "Unknown column 'cm.index' in 'where clause'". How can I pass a column value of the parent query row to the sub query?
Each row in the parent query has an index integer. I want to count the number of channel_members that have a consumption index greater than the index of each message.
Here is a sample db
SELECT read_count.*, cm.*
FROM chat_messages as cm
JOIN (SELECT b.chat_channel_id, Count(b.chat_channel_id) AS members_read
FROM channel_members b
WHERE b.consumption_index >= cm.index
GROUP BY b.chat_channel_id) read_count
ON cm.channel_id = read_count.chat_channel_id
WHERE cm.channel_id=5;
A subquery that you're joining with is not a correlated subquery, so you can't pass columns from the main query into it, they have to be related in the ON condition.
You should change the subquery to include cm.index in the grouping. Then you can join on that.
SELECT cm.*, SUM(rc.members_read) AS members_read
FROM chat_messages AS cm
JOIN (SELECT chat_channel_id, consumption_index, COUNT(*) AS members_read
FROM channel_members
GROUP BY chat_channel_id, consumption_index) AS rc
ON cm.channel_id = rc.chat_channel_id AND rc.consumption_index >= cm.index
WHERE cm.channel_id = 5
Or you could do it as a real correlated subquery, which goes in the SELECT list.
SELECT cm.*,
(SELECT COUNT(*)
FROM channel_members AS b
WHERE b.chat_channel_id = cm.channel_id AND b.consumption_index = cm.index) AS members_read
FROM chat_messages AS cm
WHERE cm.channel_id = 5