SQL - CASE WHEN result outputting conflicting results - sql

I'm working to solve
https://platform.stratascratch.com/coding/10065-find-whether-the-number-of-seniors-works-at-facebook-is-higher-than-its-number-of-usa-based-employees?python=
This is the query I've attempted to write:
SELECT CASE WHEN COUNT(CASE WHEN location = 'US' THEN 1 ELSE 0 END) >
COUNT(CASE WHEN is_senior = true THEN 1 ELSE 0 END) THEN 'More USA-based'
ELSE 'More seniors' END AS what_do_we_have_more_of
FROM facebook_employees
Result: 'More seniors'
However, when I rewrite it with the conditions flipped around:
SELECT CASE WHEN COUNT(CASE WHEN is_senior = true THEN 1 ELSE 0 END) >
COUNT(CASE WHEN location = 'US' THEN 1 ELSE 0 END) THEN 'More seniors'
ELSE 'More USA-based' END AS what_do_we_have_more_of
FROM facebook_employees
Result: 'More USA-based'
Can someone please explain why there is a discrepancy here? What is wrong with the query I've written?
I know this problem can be solved with sub-queries but I wanted to try out a CASE WHEN approach specifically. Is this more efficient?
Edit: the solution I wrote with sub-queries (works with conditions reversed)
WITH us_employees AS (
SELECT id, location
FROM facebook_employees
WHERE location = 'US'
),
senior_employees AS (
SELECT id, is_senior
FROM facebook_employees
WHERE is_senior = true
)
SELECT CASE WHEN COUNT(location) < COUNT(is_senior) THEN 'More seniors' ELSE 'More US-based' END AS what_do_we_have_more_of
FROM us_employees u
FULL JOIN senior_employees s
ON u.id = s.id
Result: 'More seniors'

The use of count() in your query is incorrect. But how do you get different results? Because both counts are the same. So A > B is always false, and you always end up in the ELSE branch.
A proper query could look like this:
SELECT CASE WHEN count(*) FILTER (WHERE location = 'US')
> count(*) FILTER (WHERE is_senior) THEN 'More USA-based'
WHEN count(*) FILTER (WHERE location = 'US')
< count(*) FILTER (WHERE is_senior) THEN 'More seniors'
ELSE 'US-based and seniors tie' END AS what_do_we_have_more_of
FROM facebook_employees;
See:
Aggregate columns with additional (distinct) filters
Note, this can never fail with NULL values, because count() (unlike most aggregate functions) never returns NULL.

You should use SUM instead of COUNT.
COUNT will count +1 even when your CASE return 1 or 0.
SUM only count +1 when your CASE return 1.
So assume that your table has 1000 rows, then both your two queries will be CASE 1000 > 1000 THEN ... ELSE... END.

Related

How to check unique values in SQL

I have a table named Bank that contains a Bank_Values column. I need a calculated Bank_Value_Unique column to shows whether each Bank_Value exists somewhere else in the table (i.e. whether its count is greater than 1).
I prepared this query, but it does not work. Could anyone help me with this and/or modify this query?
SELECT
CASE
WHEN NULLIF(LTRIM(RTRIM(Bank_Value)), '') =
(SELECT Bank_Value
FROM [Bank]
GROUP BY Bank_Value
HAVING COUNT(*) = 1)
THEN '0' ELSE '1'
END AS Bank_Key_Unique
FROM [Bank]
A windowed count should work:
SELECT
*,
CASE
COUNT(*) OVER (PARTITION BY Bank_Value)
WHEN 1 THEN 1 ELSE 0
END AS Bank_Value_Unique
FROM
Bank
;
It works also, but I found solution also:
select CASE WHEN NULLIF(LTRIM(RTRIM(Bank_Value)),'') =
(select Bank_Value
from Bank
group by Bank_Value
having (count(distinct Bank_Value) > 2 )) THEN '1' ELSE '0' END AS
Bank_Value_Uniquness
from Bank
It was missing "distinct" in having part.

posgresql exclude zero division error results

I am executing a query but for sum cases
SUM( CASE WHEN dismissal_kind = 'caught' THEN 1 ELSE 0 END )
this part of the code results into zero which causes zero division error.I am trying to not show result(not select) when
SUM( CASE WHEN dismissal_kind = 'caught' THEN 1 ELSE 0 END )
Pease help.
"""select distinct bowler as b,
count(bowler)/SUM( CASE WHEN dismissal_kind = 'caught' THEN 1 ELSE 0 END ) from deliveries
group by bowler; """
You can do it this way, by using case when:
In my example i put the default value to 0 but you can have a default value different depending on your use case
select distinct bowler as b,
case when SUM( CASE WHEN dismissal_kind = 'caught' THEN 1 ELSE 0 END ) <> 0
then
count(bowler)/SUM( CASE WHEN dismissal_kind = 'caught' THEN 1 ELSE 0 END )
else
0
end
from deliveries
group by bowler;
The simplest way is to remove the else 0:
SUM( CASE WHEN dismissal_kind = 'caught' THEN 1 END )
This returns NULL if nothing matches the condition. Dividing by NULL produces NULL and not an error.
For your query however, I recommend:
select bowler as b,
count(*) / nullif(count(*) filter (where dismissal_kind = 'caught'), 0)
from deliveries
group by bowler;
nullif() is another way to avoid division by zero. filter is the recommended (and standard) syntax for conditional aggregation.
If you want to filter out the rows that are null, you can include a having clause:
select bowler as b,
count(*) / nullif(count(*) filter (where dismissal_kind = 'caught'), 0)
from deliveries
group by bowler
having count(*) filter (where dismissal_kind = 'caught') > 0;

Oracle SQL: Using COUNT() >1 When Combining two CASE WHEN Statements

I have a line of SQL which produces a count of purchases variable
count(distinct case when t.transaction_sub_type =1 then t.transaction_date end) as COUNTPUR,
I need to modify this so I can produce a 0/1 flag variable, which flags if a customer is a repeat purchaser. So, when a customer's purchases are greater than 1 then flag as 1 else flag as 0.
case when COUNTPUR>1 then 1 else 0 end as FLAG_REPEATPURCHASER
I need to combine these two case statements into one. I have been experimenting with different versions of the syntax, but I can't seem to nail it down. Below is one of the experiments which do not work.
max(case when (count(distinct case when t.transaction_sub_type =1 then t.transaction_date end))>1 then 1 else 0 end) as FLAG_REPEATPURCHASER,
Thanks in advance for assitance
You can use a case expression with conditional aggregation:
(case when count(distinct case when t.transaction_sub_type = 1 then t.transaction_date end) > 1
then 1 else 0
end) as FLAG_REPEATPURCHASER

Apply where clause within count in sql

SELECT
Rooms.Building,
Count(Rooms.Room) AS TotalApartments,
Count(Rooms.Room) AS ApartmentsOccupied
FROM
Rooms
WHERE
(((Rooms.AssetType) <> 'LC'))
GROUP BY
Rooms.Building;
I want to count Rooms.Room Where Rooms.Occupied = True (ApartmentsOccupied) but when I put this clause into my sql it also applies the where to the TotalApartments column
You can move some logic into CASE statements to do conditional summarization:
SELECT
Rooms.Building,
Count(Rooms.Room) AS TotalApartments,
Sum(CASE WHEN Rooms.Occupied = True THEN 1 ELSE 0 END) AS ApartmentsOccupied
FROM
Rooms
WHERE
(((Rooms.AssetType) <> 'LC'))
GROUP BY
Rooms.Building;
I'm not sure off the top of my head, but you might need to change that count to a SUM as well:
Sum(1) AS TotalApartments
And alternately, in some sql dialects the 'True' value is 1, so you could get away with something like this for the occupied count:
Sum(Rooms.Occupied) AS ApartmentsOccupied
You can do like this
SELECT
Building,
Count(Room) AS TotalApartments,
SUM(CASE WHEN Occupied = True THEN 1 ELSE 0 END) AS ApartmentsOccupied
FROM
Rooms
WHERE
AssetType <> 'LC'
GROUP BY
Building;

How to do a SUM() inside a case statement in SQL server

I want to add some calculation inside my case statement to dynamically create the contents of a new column but I get the error:
Column 'Test1.qrank' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
This is the code I'm working on
case
when test1.TotalType = 'Average' then Test2.avgscore
when test1.TotalType = 'PercentOfTot' then (cnt/SUM(test1.qrank))
else cnt
end as displayscore
I did try to group but it didn't work.
Any hints?
The error you posted can happen when you're using a clause in the GROUP BY statement without including it in the select.
Example
This one works!
SELECT t.device,
SUM(case when transits.direction = 1 then 1 else 0 end) ,
SUM(case when transits.direction = 0 then 1 else 0 end) from t1 t
where t.device in ('A','B') group by t.device
This one not (omitted t.device from the select)
SELECT
SUM(case when transits.direction = 1 then 1 else 0 end) ,
SUM(case when transits.direction = 0 then 1 else 0 end) from t1 t
where t.device in ('A','B') group by t.device
This will produce your error complaining that I'm grouping for something that is not included in the select
Please, provide all the query to get more support.
You could use a Common Table Expression to create the SUM first, join it to the table, and then use the WHEN to to get the value from the CTE or the original table as necessary.
WITH PercentageOfTotal (Id, Percentage)
AS
(
SELECT Id, (cnt / SUM(AreaId)) FROM dbo.MyTable GROUP BY Id
)
SELECT
CASE
WHEN o.TotalType = 'Average' THEN r.avgscore
WHEN o.TotalType = 'PercentOfTot' THEN pt.Percentage
ELSE o.cnt
END AS [displayscore]
FROM PercentageOfTotal pt
JOIN dbo.MyTable t ON pt.Id = t.Id
If you're using SQL Server 2005 or above, you can use the windowing function SUM() OVER ().
case
when test1.TotalType = 'Average' then Test2.avgscore
when test1.TotalType = 'PercentOfTot' then (cnt/SUM(test1.qrank) over ())
else cnt
end as displayscore
But it'll be better if you show your full query to get context of what you actually need.