Why cant the Count() operator be used in a where clause? how do i get around this? - sql

I'm trying to write a query to return the town, and the number of runners from each town where the number of runners is greater than 5.
My Query right now look like this:
select hometown, count(hometown) from marathon2016 where count(hometown) > 5 group by hometown order by count(hometown) desc;
but sqlite3 responds with this:
Error: misuse of aggregate: count()
What am i doing wrong, Why cant I use the count() here, and what should I use instead.

When you're trying to use an aggregate function (such as count) in a WHERE cause, you're usually looking for HAVING instead of WHERE:
select hometown, count(hometown)
from marathon2016
group by hometown
having count(*) > 5
order by count(*) desc
You can't use an aggregate in a WHERE cause because aggregates are computed across multiple rows (as specified by GROUP BY) but WHERE is used to filter individual rows to determine what row set GROUP BY will be applied to (i.e. WHERE happens before grouping and aggregates apply after grouping).

Try the following:
select
hometown,
count(hometown) as hometown_count
from
marathon2016
group by
hometown
having
hometown_count > 5
order by
hometown_count desc;

Related

SQL Sum Total with multiple assignments

select dc_id, whse_id, assg_id, START_DTIM,
UNIT_SHIP_CSE*prod_cub as TOTAL_CUBE
from exehoust.aseld
I attached a photo to show how the query currently populates. I want to sum the TOTAL_CUBE for each distinct ASSG_ID. I have tried case where sum and group by but keep failing. Basically want to do a SUM IF for each distinct ASSG_ID
You need to group by the assg_id, but ou need also the define what happens to all the other columns i choose MIN only to give you a hint, you need to choose the function yourself
select MIN(dc_id), MIN(whse_id), assg_id, MIN(START_DTIM),
SUM(UNIT_SHIP_CSE*prod_cub) as TOTAL_CUBE
from exehoust.aseld
GROUP BY assg_id
use select assg_id, sum() over(partition by assg_id order by assg_id) to sum by groupings

How to count Boolean changes in PostgreSQL

My table looks like this
The goal is to count how many times the actuator_state of an specific actuator (from the column actuator_names) changes in a period of time. Keep in mind that a specific actuator has various actuators (For instance Heater has Heator0, Heator1, etc) and the goal is to count how many times has changed Heater0+ Heater1+ Heator2+ Heater3.... (Also the name of the table is state_actuator
I tried this:
SELECT actuator_nome AS NOME,
SUM (DISTINCT CASE WHEN actuator_state.actuator AND DISTINCT actuator_state.actuator_time AND DISTINCT actuator_state.actuator_state THEN 1 ELSE 0) AS TROCAS_ESTADO
FROM actuator_state WHERE actuator_time BETWEEN '2020-05-17 16:58:54' AND '2020-05-17 17:09:58' AND actuator_name='Heater'
The result should be
Heater: 5;
(for instance Heater0 has changed 3 times and Heater1 two times and other Heaters 0 changes)
You can use window functions for this:
select
actuator_name,
count(*) filter(where actuator_state <> lag_actuator_state) no_changes
from (
select
t.*,
lag(actuator_state)
over(partition by actuator_name, actuator order by actuator_time) lag_actuator_state
from mytable t
where actuator_time between '2020-05-17 16:58:54' and '2020-05-17 17:09:58'
) t
group by actuator_name
The subquery uses lag() to retrieve the "previous" state of each actuator. Then, the outer query aggregates by actuator_name, and performs a count that increments by 1 everytime the consecutive values are not equal.
You can add additional filters in the where clause of the subquery as needed.
Note that this query does not count the first value in the period as a change. Only further changes are taken into account.
You can use lag():
select actuator_name,
count(*) filter (where prev_as is distinct from actuator_state)
from (select sa.*,
lag(actuator_state) over (partition by actuator order by actuator_time) as prev_as
from state_actuator sa
) sa
where actuator_time between '2020-05-17 16:58:54' and '2020-05-17 17:09:58'
group by actuator_name;
You can filter on a particular name in the where clause as well.
Note that this counts the first appearance as a "change". It is not clear if that matches your intention.

oracle decode group by warning

I have this code
for x_eo in ( select decode(mod(card_name_id,2),0,1,1,2) e_o, count(*) nr
from rp_Deck where session_id=p_session_id_in
and position<=35 group by mod(card_name_id,2) )
I am getting sqldeveloper warning that select list inconsistent with group by.
And developer gives me solution:
select decode(mod(card_name_id,2),0,1,1,2) e_o, count(*) nr
from rp_Deck where session_id=p_session_id_in
and position<=35 group by mod(card_name_id,2), card_name_id, 2, decode(mod(card_name_id,2),0,1,1,2) )
What is difference between these two group by ?
Thanks !
In general, when you use GROUP BY in a statement then all the values either need to be:
constants;
within aggregation functions; or
in the GROUP BY clause.
SQL Developer does not realise that decode(value_mod_2,0,1,1,2) is effectively just adding 1 to the value and does not change the allocation of items to groups so, since it is not either a constant or an aggregation function, it expects the entire function to be in the GROUP BY clause.
Personally, I would write it as:
select mod(card_name_id,2) + 1 e_o,
count(*) nr
from rp_Deck
where session_id=p_session_id_in
and position<=35
group by mod(card_name_id,2)
(the + 1 is a constant so does not need to be in the GROUP BY clause)
The solution SQL Developer proposes is wrong as:
select decode(mod(card_name_id,2),0,1,1,2) e_o,
count(*) nr
from rp_Deck
where session_id=p_session_id_in
and position<=35
group by
mod(card_name_id,2),
card_name_id,
2,
decode(mod(card_name_id,2),0,1,1,2)
is effectively the same as just grouping by the finest grained grouping, so:
group by card_name_id;
Which is not what you want to group by. To be the same as your original query's intended output, it should propose something like:
group by
mod(card_name_id,2),
decode(mod(card_name_id,2),0,1,1,2)
or more simply just:
group by
decode(mod(card_name_id,2),0,1,1,2)

...oracle group by syntax for beginners

What is the problem in this please?
select inst.id
, inst.type as "TypeOfInstall"
, count(inst.id) as "NoOfInstall"
from dm_bsl_ho.installment inst
group by inst.type
You're not allowed to use single function with group function. Like mixing count with single row function.
You should include the group by function:
select inst.type as "TypeOfInstall"
, count(inst.id) as "NoOfInstall"
from dm_bsl_ho.installment inst
GROUP BY inst.type;
When you do a GROUP BY in most RDBMSs, your selection is limited to the following two things:
Columns mentioned in the GROUP BY - in your case, that's inst.type
Aggregate functions - for example, count(inst.id)
However, the inst.id at the top is neither one of these. You need to remove it for the statement to work:
SELECT
type as "TypeOfInstall"
, COUNT(id) as "NoOfInstall"
FROM dm_bsl_ho.installment
GROUP BY type

Group by SQL statement

So I got this statement, which works fine:
SELECT MAX(patient_history_date_bio) AS med_date, medication_name
FROM biological
WHERE patient_id = 12)
GROUP BY medication_name
But, I would like to have the corresponding medication_dose also. So I type this up
SELECT MAX(patient_history_date_bio) AS med_date, medication_name, medication_dose
FROM biological
WHERE (patient_id = 12)
GROUP BY medication_name
But, it gives me an error saying:
"coumn 'biological.medication_dose' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.".
So I try adding medication_dose to the GROUP BY clause, but then it gives me extra rows that I don't want.
I would like to get the latest row for each medication in my table. (The latest row is determined by the max function, getting the latest date).
How do I fix this problem?
Use:
SELECT b.medication_name,
b.patient_history_date_bio AS med_date,
b.medication_dose
FROM BIOLOGICAL b
JOIN (SELECT y.medication_name,
MAX(y.patient_history_date_bio) AS max_date
FROM BIOLOGICAL y
GROUP BY y.medication_name) x ON x.medication_name = b.medication_name
AND x.max_date = b.patient_history_date_bio
WHERE b.patient_id = ?
If you really have to, as one quick workaround, you can apply an aggregate function to your medication_dose such as MAX(medication_dose).
However note that this is normally an indication that you are either building the query incorrectly, or that you need to refactor/normalize your database schema. In your case, it looks like you are tackling the query incorrectly. The correct approach should the one suggested by OMG Poinies in another answer.
You may be interested in checking out the following interesting article which describes the reasons behind this error:
But WHY Must That Column Be Contained in an Aggregate Function or the GROUP BY clause?
You need to put max(medication_dose) in your select. Group by returns a result set that contains distinct values for fields in your group by clause, so apparently you have multiple records that have the same medication_name, but different doses, so you are getting two results.
By putting in max(medication_dose) it will return the maximum dose value for each medication_name. You can use any aggregate function on dose (max, min, avg, sum, etc.)