SQL Case Statement or Different Method? - sql

I will be using my output to place into an Excel pivot table. The data is dealing with credit accounts that have either charged off or not.
EDIT: If chargeoffs is checked in the pivot table I want the totalaccounts column to be a count of total accounts regardless of the chargeoffdate value. If chargeoffs is left unchecked I want totalaccounts to be a count of all accounts when chargeoffdate is NULL.
Here is my SQL syntax so far:
SELECT
c.brand,
CASE WHEN a.chargeoffdate IS NULL THEN 'No Chargeoffs'
-- Below here should not be only chargeoffs, it should be chargeoffs + the column above ^^^
WHEN a.chargeoffdate IS NOT NULL THEN 'Chargeoffs'
ELSE 'Unknown' END AS chargeoffs,
COUNT(*) AS totalaccounts
FROM accounts
GROUP BY brand, chargeoffs
You can see the comment in my SQL to understand what I am going for, but I can't figure out how to accomplish this.
I tried:
CASE WHEN a.chargeoffdate IS NULL THEN 'No Chargeoffs'
-- Below here should not be only chargeoffs, it should be chargeoffs + the column above ^^^
WHEN (a.chargeoffdate IS NOT NULL OR a.chargeoffdate IS NULL) THEN 'Chargeoffs Included'
ELSE 'Unknown' END AS chargeoffs
But got the same results as the top query for some reason. Thanks.
ANOTHER EDIT: OUTPUT DESIRED
BRAND 1 | WITH CHARGEOFFS | COUNT(TOTALACCOUNTS)
BRAND 1 | WITHOUT CHARGEOFFS | COUNT(TOTALACCOUNTS)
BRAND 2 | WITH CHARGEOFFS | COUNT(TOTALACCOUNTS)
BRAND 2 | WITHOUT CHARGEOFFS | COUNT(TOTALACCOUNTS)

Updated:
Chargeoffs = Count of all accounts whether chargeoffdate is null or not
No Chargeoffs = Count of all accounts where chargeoffdate is null (they haven't charged off)
SELECT
brand,
count(*) as "Chargeoffs",
sum(CASE WHEN a.chargeoffdate IS NULL THEN 1 ELSE 0 END) as 'No Chargeoffs'
FROM accounts
GROUP BY brand
UPDATE: I'm tired, I obtained this long SQL, wich is near what you want:
SELECT brand,
tp,
CASE WHEN TP = 1 then sum(cnt) END as 'No Chargeoffs',
sum(cnt) as "Chargeoffs"
FROM(
SELECT
brand,
CASE WHEN a.chargeoffdate IS NULL THEN 1 ELSE 0 END as tp
count(*) as cnt
FROM accounts
GROUP BY brand, CASE WHEN a.chargeoffdate IS NULL THEN 1 ELSE 0 END
GROUP BY brand, tp

That was kind of stupid and my solution was easy. I just left it how I had it and the pivot table added them together for me.
I found this out after I had created 2 separate queries and did some data manipulation with SAS to get what I wanted. Ouch.

Related

Subtract 2 case statements

I am trying to subtract the 2 case statements like this:
CASE
WHEN fct.measure IN ('A')
THEN fct.month_value
ELSE NULL
END
- CASE
WHEN fct.measure IN ('B')
THEN fct.month_value
ELSE NULL
END AS discounts
This query doesn't throw a syntax error, but it returns all NULL.
The month_value corresponding to A is 3173.100000 and the month value corresponding to B is 8043.000000.
Any suggestions on how this could return the correct result instead of all NULL?
I presume that you need some kind of conditional aggregation approach here:
SELECT
col,
MAX(CASE WHEN measure = 'A' THEN month_value END) -
MAX(CASE WHEN measure = 'B' THEN month_value END);
FROM yourTable
GROUP BY col;
This assumes that your table structure looks something like the following:
col | measure | month_value
1 | A | 3173.10
1 | B | 8043.00
We aggregate by each col value, and then use conditional aggregation to isolate the various month values based on the value of the measure column.

check and compare the count from two tables without relation

I have below tables
Table1: "Demo"
Columns: SSN, sales, Create_DT,Update_Dt
Table2: "Agent"
Columns: SSN,sales, Agent_Name, Create_Dt, Update_DT
Scenario 1 and desired result set:
I want output as 0 if the count of SSN in Demo table is matched with the count of SSN in Agent table
if the count is not matched then I want result as 1
Scenario 2 and desired result set:
I want output as 0 if the sum of sales in Demo table is matched with the sum of sales in Agent table
if the sum is not matched then I want result as 1
Please help on this query part
Thanks
You can write two queries separately to take counts within the result query
SELECT (SELECT count(Demo.SSN) as SSN1 from Demo)!=(SELECT count(Agent.SSN) as SSN2 from Agent) AS Result;
Basically what the inner queries does is it checked whether the counts are equal or not and outputs 1 if it is true and 0 if it is false. Since you have asked to output 1 if it is false I used '!=' sign.
You can try the same procedure in scenario 2 also
For scenario 1
select (Case when (select count(ssn) from Demo)=(select count(ssn) from Agent) then 0 else 1 end) as desired_result
If you want to count unique ssn then:
select (Case when (select count(distinct ssn) from Demo)=(select count(distinct ssn) from Agent) then 0 else 1 end) as desired_result
For scenario 2:
select (Case when (select sum(sales) from Demo)=(select sum(sales) from Agent) then 0 else 1 end) as desired_result
I would suggest one query with both sets of information:
select (d.num_ssn <> a.num_ssn) as have_different_ssn_count,
(d.sales <> a.sales) as have_different_sales
from (select count(distinct ssn) as num_ssn,
coalesce(sum(sales), 0) as sales
from demo
) d cross join
(select count(distinct ssn) as num_ssn,
coalesce(sum(sales), 0) as sales
from agent
) a;
Note: This returns boolean values -- true/false rather than 1/0. If you really want 0/1, then use case:
select (case when d.num_ssn <> a.num_ssn then 1 else 0 end) as have_different_ssn_count,
(case when d.sales <> a.sales then 1 else 0 end) as have_different_sales
It would not surprise me if you were not only interested in the total counts but also that the agent/sales combinations are the same in both tables. If that is the case, please ask a new question with a clear explanation. Sample data and desired results help.

SQL query syntax in CASE WHEN ELSE END to count

Writing a query to find the number of ED visits that were discharged from non-ED units.
The column dep.ADT_UNIT_TYPE_C column stores 1 if the unit was an ED unit.
Assume NULL values are non-ED units for the purpose of this query.
Which of the following produces this number?
I am thinking it is A because in my mind, that sound the correct syntax.
COUNT(CASE WHEN THEN ELSE END standard format)
A has that.
B doesn't have the THEN? so it is incorrect syntax?
Please help me understanding the nuances between these choices.
A.)
COUNT( CASE WHEN dep.ADT_UNIT_TYPE_C is NULL OR dep.ADT_UNIT_TYPE_C <> 1 THEN NULL
ELSE 1
END )
B.)
COUNT( CASE WHEN dep.ADT_UNIT_TYPE_C is NULL or dep.ADT_UNIT_TYPE_C <> 1
ELSE NULL
END)
C.)
CASE WHEN dep.ADT_UNIT_TYPE_C Is NULL or dep.ADT_UNIT_TYPE_C <> 1 THEN COUNT (NULL)
ELSE COUNT (1)
END
D.)
CASE WHEN dep.ADT_UNIT_TYPE_C is NULL or dep.ADT_UNIT_TYPE_C <> 1 THEN COUNT(1)
ELSE COUNT(NULL)
END
You can count the records that are returned COUNT(*) and put the condition in the where clause.
If you are using Oracle, you can use NVL.
The sample below is for Oracle, but if using mysql or SQL server, you can use the ISNULL Function.
SELECT COUNT(*) FROM dep WHERE NVL(ADT_UNIT_TYPE_C, 0) != 1
It looks like however, you are joining this to another table, probably a visit table. So, you want to count visits. Visits probably stores some kind of department id or way to join it to departments.
Something like this:
SELECT COUNT(*) FROM visit v, departments d WHERE v.dep_id = d.dep_id AND NVL(d.ADT_UNIT_TYPE_C, 0) !=1
If you want the entire list like shown above, you want to use a group by. This will show you the count for each visit by department type.
SELECT COUNT(*) FROM visit v, departments d GROUP BY d.ADT_UNIT_TYPE_C

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.

Group by multiple criteria

Given the table like
| userid | active | anonymous |
| 1 | t | f |
| 2 | f | f |
| 3 | f | t |
I need to get:
number of users
number of users with 'active' = true
number of users with 'active' = false
number of users with 'anonymous' = true
number of users with 'anonymous' = false
with single query.
As for now, I only came out with the solution using union:
SELECT count(*) FROM mytable
UNION ALL
SELECT count(*) FROM mytable where active
UNION ALL
SELECT count(*) FROM mytable where anonymous
So I can take first number and find non-active and non-anonymous users with simple deduction .
Is there any way to get rid of union and calculate number of records matching these simple conditions with some magic and efficient query in PostgreSQL 9?
You can use an aggregate function with a CASE to get the result in separate columns:
select
count(*) TotalUsers,
sum(case when active = 't' then 1 else 0 end) TotalActiveTrue,
sum(case when active = 'f' then 1 else 0 end) TotalActiveFalse,
sum(case when anonymous = 't' then 1 else 0 end) TotalAnonTrue,
sum(case when anonymous = 'f' then 1 else 0 end) TotalAnonFalse
from mytable;
See SQL Fiddle with Demo
Assuming your columns are boolean NOT NULL, this should be a bit faster:
SELECT total_ct
,active_ct
,(total_ct - active_ct) AS not_active_ct
,anon_ct
,(total_ct - anon_ct) AS not_anon_ct
FROM (
SELECT count(*) AS total_ct
,count(active OR NULL) AS active_ct
,count(anonymous OR NULL) AS anon_ct
FROM tbl
) sub;
Find a detailed explanation for the techniques used in this closely related answer:
Compute percents from SUM() in the same SELECT sql query
Indexes are hardly going to be of any use, since the whole table has to be read anyway. A covering index might be of help if your rows are bigger than in the example. Depends on the specifics of your actual table.
-> SQLfiddle comparing to #bluefeet's version with CASE statements for each value.
SQL server folks are not used to the proper boolean type of Postgres and tend to go the long way round.