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

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

Related

SQL - CASE WHEN result outputting conflicting results

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.

Using a case statement to show the count of two types of values in a column

SELECT
qt.name,
CASE
WHEN qr.isfinished = 0 THEN COUNT(qr.resultid)
END AS 'Attempted',
CASE
WHEN qr.isfinished = 1 THEN COUNT(qr.resultid)
END AS 'Completed'
Need it to show attempted and completed values on the same row
Name attempted Completed
--------------------------------
Algebra I 114 NULL
Algebra II 47 NULL
ASVAB 55 NULL
Algebra I NULL 69
Algebra II NULL 55
ASVAB NULL 84
Thank you for the help!
If isfinished is bit, you can't aggregate on it.
And the CASE goes inside the COUNT
SELECT qt.name,
count(Case when qr.isfinished = 0 THEN 1 END) as 'Attempted',
count(Case when qr.isfinished = 1 THEN 1 END) as 'Completed'
FROM
...
GROUP BY
qt.name
There are multiple ways you could do this, for example you could do this with joins, or you can use group by -- like so:
SELECT
qt.name,
SUM(CASE qr.isfinsihed WHEN 1 THEN 1 ELSE 0) AS 'Attempted',
SUM(CASE qr.isfinished WHEN 0 THEN 1 ELSE 0) AS 'Completed'
FROM -- what ever your from clause is, it goes here --
GROUP BY
qt.name
In order to have them on the same row, you will need to group by what they have in common. From what you have given in the question, I am assuming that is the qt.name.
Next, you can use the SUM aggregate to get each field count. All of the records that meet the criteria for each item count towards the sum, the others don't. You can also use count with 1's and Null's, I prefer using Sum because it can allow for weighted totals if I need them.

Multiple SUM values using WHERE clauses in Oracle

I am writing a SQL statement against an Oracle 10g database. I want to obtain the SUM of a field with three different conditions. Can I do this with one query?
This is pseudo-SQL for what I want:
SELECT SUM(CP) AS CPTotal,
(SUM(CP) FROM tasks WHERE Code='P') AS CPProd,
(SUM(CP) FROM tasks WHERE Code='S') AS CPSupp
FROM tasks;
A conditional SUM() can be had via CASE statements:
SELECT SUM(CP) AS CPTotal,
SUM(CASE WHEN Code = 'P' THEN CP ELSE 0 END) AS CPProd,
SUM(CASE WHEN Code = 'S' THEN CP ELSE 0 END) AS CPSupp
FROM tasks;
The ELSE portion is not needed as NULL results when a value does not match any criteria in a CASE statement, and NULL is ignored on aggregation, but some prefer to include it.
You can use CASE to conditional check for the value of code.
SELECT SUM(CP) AS CPTotal,
SUM(CASE WHEN Code = 'P' THEN CP END) AS CPProd,
SUM(CASE WHEN Code = 'S' THEN CP END) AS CPSupp
FROM tasks

SQL 2 counts with different filter

I have a table and I need calculate two aggregate functions with different conditions in one statement. How can I do this?
Pseudocode below:
SELECT count(CoumntA) *< 0*, count(CoumntA) * > 0*
FROM dbo.TableA
This is the same idea as tombom's answer, but with SQL Server syntax:
SELECT
SUM(CASE WHEN CoumntA < 0 THEN 1 ELSE 0 END) AS LessThanZero,
SUM(CASE WHEN CoumntA > 0 THEN 1 ELSE 0 END) AS GreaterThanZero
FROM TableA
As #tombom demonstrated, this can be done as a single query. But it doesn't mean that it should be.
SELECT
SUM(CASE WHEN CoumntA < 0 THEN 1 ELSE 0 END) AS less_than_zero,
SUM(CASE WHEN CoumntA > 0 THEN 1 ELSE 0 END) AS greater_than_zero
FROM
TableA
The time when this is not so good is...
- There is an index on CoumntA
- Most values (50% or more feels about right) are exactly zero
In that case, two queries will be faster. This is because each query can use the index to quickly home in on the section to be counted. In the end only counting the relevant records.
The example I gave, however, scans the whole table every time. Only once, but always the whole table. This is worth it when you're counting most of the records. In your case it looks liek you're counting most or all of them, and so this is probably a good way of doing it.
It is possible to do this in one select statement.
The way I've done it before is like this:
SELECT SUM(CASE WHEN ColumnA < 0 THEN 1 END) AS LessThanZero,
SUM(CASE WHEN ColumnA > 0 THEN 1 END) AS GreaterThanZero
FROM dbo.TableA
This is the correct MS SQL syntax and I believe this is a very efficient way of doing it.
Don't forget you are not covering the case when ColumnA = 0!
select '< 0' as filter, COUNT(0) as cnt from TableA where [condition 1]
union
select '> 0' as filter, COUNT(0) as cnt from TableA where [condition 2]
Be sure that condition 1 and condition 2 create a partition on the original set of records, otherwise same records could be counted in both groups.
For SQL Server, one way would be;
SELECT COUNT(CASE WHEN CoumntA<0 THEN 1 ELSE NULL END),
COUNT(CASE WHEN CoumntA>0 THEN 1 ELSE NULL END)
FROM dbo.TableA
Demo here.
SELECT
SUM(IF(CoumntA < 0, 1, 0)) AS lowerThanZero,
SUM(IF(CoumntA > 0, 1, 0)) AS greaterThanZero
FROM
TableA
Is it clear what's happening? Ask, if you have any more questions.
A shorter form would be
SELECT
SUM(CoumntA < 0) AS lowerThanZero,
SUM(CoumntA > 0) AS greaterThanZero
FROM
TableA
This is possible, since in MySQL a true condition is equal 1, a false condition is equal 0
EDIT: okay, okay, sorry, don't know why I thought it's about MySQL here.
See the other answers about correct syntax.

aggregations in case statement

I am trying to do aggregations in case statement. I found 2 ways to do it. Can anyone say what the difference between the 2 is?
(CASE WHEN Event = 5 THEN count(*) ELSE 0 END ) Follow_Count
GROUP BY Event;
SUM(CASE Event WHEN 5 THEN 1 ELSE 0 END) AS Follow_Count
Your case 1 will produce a row for each event in the table (from your group by). Your case 2 will just return 1 row.
Is there a reason that you wouldn't just write:
select count(*)
from my_table
where event = 5;
Better would be:
count(CASE Event WHEN 5 THEN 1 END) AS Follow_Count
Because
1) for count used own standart counter,
2) "else" not need (count don't count nulls)
Regards,
Sayan M.
There is no significant difference. You can decide for you which is better by comparing their execution plans.