Use count value in clause WHERE - mysql

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.

Related

MySQL Error: 1111 (Invalid use of group function) [duplicate]

This question already has an answer here:
ERROR 1111 (HY000): Invalid use of group function
(1 answer)
Closed 1 year ago.
I'm not yet good at MySQL. Please check my sql below and help me understand where I went wrong with it. All I need is just one record for the order.id and the returned record must be the one whose shipped date is the latest.
Database error: Invalid SQL: SELECT orders.id, orders.customer_fk FROM orders INNER JOIN order_details ON order_details.order_fk=orders.id WHERE orders.payment_method IN ('AS','AC') AND ((orders.order_status='SHP' AND order_details.item_status='SHP' AND MAX(order_details.shipped_date) <= '2021-08-07') OR (orders.order_status='CAN' AND orders.order_date <= '2021-08-07 09:56:18')) AND orders.pii_status <> '1'GROUP BY orders.id
MySQL Error: 1111 (Invalid use of group function)
Instead of using MAX alone try to use a subselect
If you don't want the mad for every order.id then you need to add a inner join
SELECT
orders.id, orders.customer_fk
FROM
orders
INNER JOIN
order_details ON order_details.order_fk = orders.id
WHERE
orders.payment_method IN ('AS' , 'AC')
AND ((orders.order_status = 'SHP'
AND order_details.item_status = 'SHP'
AND (SELECT MAX(shipped_date) FROM order_details WHERE order_fk = orders.id) <= '2021-08-07')
OR (orders.order_status = 'CAN'
AND orders.order_date <= '2021-08-07 09:56:18'))
AND orders.pii_status <> '1'
GROUP BY orders.id
To explain it somewhat further
SELECT MAX(shipped_date) FROM order_details WHERE order_fk = orders.id) <= '2021-08-07'
Return true or false for every Order.id as it checks for every row in the outer select what the maximum date is and then checks it against the date.
After selecting all rows you GROUP BY(which i still don't get as you have no aggregation function it) comes for every order.id.
Maybe you should try a DISTINCT
You select both orders.id and orders.customer_fk, but you group by orders.id only. When using group by in SQL, all other columns not present in the group by clause must be aggregate functions, since for example in this current case you group the results by the order id, meaning there can be only one row per unique order id among the results.
And something has to happen with the list of values of the other column that all belong to this one grouped order id, this is where the aggregations come in. If it is a number you can calculate the MIN/MAX/AVG etc. of these, but the simplest aggregate is to just count the matching results.
So if you wanted your query to return the number of order.customer_fk for each unique order.id, just add SELECT orders.id, COUNT(orders.customer_fk).
Otherwise, if you didn't intend to group your results, you can remove the GROUP BY clause, or replace it with an ORDER BY.
If you want to filter using aggregation functions use having. However, I'm guessing that you just want to filter by the date:
SELECT o.id, o.customer_fk
FROM orders o INNER JOIN
order_details od
ON od.order_fk= o.id
WHERE o.payment_method IN ('AS','AC') AND
((o.order_status = 'SHP' AND od.item_status='SHP' AND od.shipped_date <= '2021-08-07') OR
(o.order_status = 'CAN' AND o.order_date <= '2021-08-07 09:56:18')
) AND
o.pii_status <> '1'
GROUP BY o.id

MySQL Count as {name} and WHERE {name} = X, Unknown column

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

SQL Query to not display null values

I have managed to hack an SQL Query together and it was working until I realised some members in the database have null names due to the plugin we are using removes non-ascii names. I am displaying these stats on my page and having someone with no name doesn't work too well. I know how to not display NULL when using the WHERE clause but i'm not too sure when no WHERE clause is used.
What I have so far -
SELECT player_stats.player_name, COUNT(player_kill.killer)
FROM player_stats
LEFT JOIN player_kill ON player_stats.player_id = player_kill.killer
GROUP BY player_stats.player_name
HAVING COUNT(player_kill.killer) > 1
ORDER BY COUNT(player_kill.killer) DESC;
The WHERE clause goes between all the JOIN clauses and GROUP BY. If WHERE player_name IS NOT NULL isn't working, the names are probably empty strings, not NULL, so you need to check for that as well.
SELECT s.player_name, COUNT(*) AS count
FROM player_stats AS s
INNER JOIN player_kill AS k ON s.player_id = k.killer
WHERE s.player_name IS NOT NULL AND s.player_name != ''
GROUP BY s.player_name
ORDER BY count DESC;
Also, if you don't want to get 0 counts, use INNER JOIN rather than LEFT JOIN.
If you don't want to change your query to much you can replace the players name by checking if it's null.
SELECT ISNULL(s.player_name, "RandomPlayer"), COUNT(*) AS count
FROM player_stats AS s
INNER JOIN player_kill AS k ON s.player_id = k.killer
WHERE s.player_name IS NOT NULL AND s.player_name != ''
GROUP BY s.player_name
ORDER BY count DESC;
https://msdn.microsoft.com/en-us/library/ms184325.aspx

How to fix SQL query with Left Join and subquery?

I have SQL query with LEFT JOIN:
SELECT COUNT(stn.stocksId) AS count_stocks
FROM MedicalFacilities AS a
LEFT JOIN stocks stn ON
(stn.stocksIdMF = ( SELECT b.MedicalFacilitiesIdUser
FROM medicalfacilities AS b
WHERE b.MedicalFacilitiesIdUser = a.MedicalFacilitiesIdUser
ORDER BY stn.stocksId DESC LIMIT 1)
AND stn.stocksEndDate >= UNIX_TIMESTAMP() AND stn.stocksStartDate <= UNIX_TIMESTAMP())
These query I want to select one row from table stocks by conditions and with field equal value a.MedicalFacilitiesIdUser.
I get always count_stocks = 0 in result. But I need to get 1
The count(...) aggregate doesn't count null, so its argument matters:
COUNT(stn.stocksId)
Since stn is your right hand table, this will not count anything if the left join misses. You could use:
COUNT(*)
which counts every row, even if all its columns are null. Or a column from the left hand table (a) that is never null:
COUNT(a.ID)
Your subquery in the on looks very strange to me:
on stn.stocksIdMF = ( SELECT b.MedicalFacilitiesIdUser
FROM medicalfacilities AS b
WHERE b.MedicalFacilitiesIdUser = a.MedicalFacilitiesIdUser
ORDER BY stn.stocksId DESC LIMIT 1)
This is comparing MedicalFacilitiesIdUser to stocksIdMF. Admittedly, you have no sample data or data layouts, but the naming of the columns suggests that these are not the same thing. Perhaps you intend:
on stn.stocksIdMF = ( SELECT b.stocksId
-----------------------------^
FROM medicalfacilities AS b
WHERE b.MedicalFacilitiesIdUser = a.MedicalFacilitiesIdUser
ORDER BY b.stocksId DESC
LIMIT 1)
Also, ordering by stn.stocksid wouldn't do anything useful, because that would be coming from outside the subquery.
Your subquery seems redundant and main query is hard to read as much of the join statements could be placed in where clause. Additionally, original query might have a performance issue.
Recall WHERE is an implicit join and JOIN is an explicit join. Query optimizers
make no distinction between the two if they use same expressions but readability and maintainability is another thing to acknowledge.
Consider the revised version (notice I added a GROUP BY):
SELECT COUNT(stn.stocksId) AS count_stocks
FROM MedicalFacilities AS a
LEFT JOIN stocks stn ON stn.stocksIdMF = a.MedicalFacilitiesIdUser
WHERE stn.stocksEndDate >= UNIX_TIMESTAMP()
AND stn.stocksStartDate <= UNIX_TIMESTAMP()
GROUP BY stn.stocksId
ORDER BY stn.stocksId DESC
LIMIT 1

mySQL query ignoring NOT IN function

This query is processing and running but it is completely ignoring the NOT IN section
SELECT * FROM `offers` as `o` WHERE `o`.country_iso = '$country_iso' AND `o`.`id`
not in (select distinct(offer_id) from aff_disabled_offers
where offer_id = 'o.id' and user_id = '1') ORDER by rand() LIMIT 7
Maybe your "not in" query returns nothing.
Shouldn't the
where offer_id='o.id'
Be
where offer_id=o.id
?
guido has the answer... it looks like you meant to create a correlated subquery. 'o.id' is being seen as a literal.
SOME CAUTIONS:
You usually want some sort of guarantee that the subquery in the NOT IN predicate does NOT return a NULL value. If you don't have that guarantee enforced from the database, adding a WHERE/HAVING return_expr IS NOT NULL in the subquery is sufficient to give you that guarantee.
That correlated subquery is going to eat your lunch, performance wise, on large sets. As will that ORDER BY rand().
Generally, an anti-join pattern turns out to be much more efficient on large sets:
SELECT o.*
FROM offers o
LEFT
JOIN aff_disabled_offers d
ON d.user_id = '1'
AND d.offer_id = o.id
WHERE d.offer_id IS NULL
AND o.country_iso = '$country_iso'
ORDER BY rand()
LIMIT 7