count results from a case statement - count

I'm trying to figure out how to count the number of occurrences based on a case statement:
select
case
when name.ssn > 0
then 'YES'
when name.taxid > 0
then 'NO'
else 'OTHER' end "Category",
name.created
from
name
where
name.id = 11111
I now want to return the count of YESs, OTHERs, and NOs in one column but can't seem to figure out how to do that.

You just need to count the result over group by statement
select count(col),col from(
select
case
when name.ssn > 0
then 'YES'
when name.taxid > 0
then 'NO'
else 'OTHER' end as col,
name.created
from
name
where
name.id = 11111
) group by col;

Related

Teradata: Sum Total Amount of Paid Claims by Duplicate DX Flag per Member

First, I'm sure there is a cleaner way to do this, but it's the only way I've been able to make the code combine the DX's into one column. Originally they were in separate columns as 0/1's and I needed them in one column. I tried the PIVOT function, but was not able to figure it out.
The issue is I need the paid amounts to be based on duplicated instances DX's. Which sounds counterintuitive, but for this report it's what I need.
For example. If member A has COPD, ASTHMA, AND DIABETES. The member's paid claims were 40,000 so I need the paid amount for that member to reflect 120,000, etc. and so forth.
The code:
SELECT
DX_FLAG
,Sum( AMT_PAID) AS PHARM_PAID_AMT
,Count(DISTINCT(MEMBER_AMISYS_NBR)) AS MEMBER_COUNT
FROM
(SELECT
st.MEMBER_AMISYS_NBR
,ph.PHARMACY_CLAIM_CK
,ph.AMT_PAID
,FILL.DATE_DATE AS Fill_Date
,Coalesce(CASE WHEN DX_ASTHMA = 'ASTHMA' THEN 'Asthma' END,
CASE WHEN DX_COPD = 'COPD' THEN 'COPD' END,
CASE WHEN DX_DIABETES = 'DIABETES' THEN 'DIABETES' END,
CASE WHEN DX_HEART_FAILURE = 'HEART FAILURE' THEN 'HEART_FAILURE' END,
CASE WHEN DX_HYPERTENSION = 'HYPERTENSION' THEN 'HYPERTENSION' END)
AS DX_FLAG
FROM
STATE_OVERALL_MBRS st
JOIN FT_PHARMACY_CLAIM ph ON st.MEMBER_CURR_CK = ph.PRESCRIBER_MEMBER_CURR_CK AND ph.DELETED_IND = 'N'
JOIN DIM_DATE FILL ON ph.FILL_DATE_DIM_CK = FILL.DATE_DIM_CK
WHERE FILL.DATE_DATE BETWEEN '2021-10-01' AND '2022-09-30'
AND ph.PLAN_DIM_CK =10
AND ph.REVERSAL_IND = 'N'
AND ph.AMT_PAID > 0
) rx
My output looks like this .
DX_FLAG
PHARM_PAID_AMT
MEMBER_COUNT
DIABETES
70,000,000
14,144
COPD
38,266,409
6,641
HEART_FAILURE
10,908,000
2,544
ASTHMA
125,000,000
30,000
HYPERTENSION
52,900
22,325
I have tried adding/removing the Distinct from each select statement and the only one that made a difference was removing distinct from this line, in which case I ended up with far too many member counts (even taking into account the duplicate DX counts).
,Count(DISTINCT(MEMBER_AMISYS_NBR)) AS MEMBER_COUNT
The State_Overall_Mbrs table with DX_Flag looks like this and I needed all the diagnosis to be in one column (with duplicate rows for members depending on how many diagnoses they have):
Member ID Asthma COPD Hypertension Diabetes CHF
55555555 0 1 1 1 0
66666666 1 0 0 1 0
77777777 0 0 1 0 0
Normalize the members table, then join and aggregate; something like this:
SELECT
DX_FLAG
,Sum(AMT_PAID) AS PHARM_PAID_AMT
,Count(DISTINCT(MEMBER_AMISYS_NBR)) AS MEMBER_COUNT
FROM
(SELECT * FROM State_Overall_Members
UNPIVOT (has_dx /* New column to hold the 0 or 1 value */
FOR DX_FLAG IN (Asthma,COPD,Hypertension,Diabetes,CHF)
/* Original column names become the values in new column DX_FLAG */
) nmlz
WHERE has_dx = 1 /* Only unpivot rows with a 1 in original column */
) st
JOIN FT_PHARMACY_CLAIM ph ON st.MEMBER_CURR_CK = ph.PRESCRIBER_MEMBER_CURR_CK AND ph.DELETED_IND = 'N'
JOIN DIM_DATE FILL ON ph.FILL_DATE_DIM_CK = FILL.DATE_DIM_CK
WHERE FILL.DATE_DATE BETWEEN '2021-10-01' AND '2022-09-30'
AND ph.PLAN_DIM_CK =10
AND ph.REVERSAL_IND = 'N'
AND ph.AMT_PAID > 0
GROUP BY DX_FLAG;
Another option to normalize the members table would be to have a subquery for each DX and UNION those, along these lines:
... FROM
(SELECT MEMBER_CURR_CK, MEMBER_AMISYS_NBR, AMT_PAID, 'Asthma' (VARCHAR(16)) AS DX_FLAG
FROM State_Overall_Members
WHERE Asthma = 1
UNION ALL
SELECT MEMBER_CURR_CK, MEMBER_AMISYS_NBR, AMT_PAID, 'COPD' (VARCHAR(16)) AS DX_FLAG
FROM State_Overall_Members
WHERE COPD = 1
UNION ALL
...
) st
JOIN ...

SQLite - Update column of the same table, based on result from row_number()

After several tries, I was able to generate a row_number() column with the value I wished.
select "order", row_number() over win - 1, type, title, body, searched_string from plain_note
WINDOW win AS (
order by
title desc,
case when type = 0 then body else searched_string end desc
)
Now, I would like to overwrite entire "order" column, with the value from "row_number() over win - 1"
For instance,
In the 1st row, I would like to update "order" column (original value 13) with value 0.
In the 2nd row, I would like to update "order" column (original value 14) with value 1.
... and so on.
May I know, what is the correct SQLite statement to do so? Thanks.
The approach I had tried so far is
update plain_note set "order" = (
select row_number() over win - 1 from plain_note
WINDOW win AS (
order by
title desc,
case when type = 0 then body else searched_string end desc
)
);
However, this will make ALL rows of "order", having the 1st row of "row_number() over win - 1" value, which is 0.
Your code is missing a link between the table's rows and the subquery's rows.
I would write the update method like this:
with cte as (
select *, row_number() over win - 1 as rn from plain_note
window win as (order by
title desc,
case when type = 0 then body else searched_string end desc
)
)
update plain_note set "order" = (select rn from cte where "order" = plain_note."order");
This will work of the values in the column "order" are unique.

Teradata : using case statement in Where clause

My question is about using case statement in where clause to check for date and assign values to columns. My sample code include.
select * from table
where
column 1 > 10 and
case when column 2 = 1
then
column 3<= 10 and column 4 between (1st day of prev month) and (prev month end) or column 5 = '8888-01-01'
else
column 4 between (1st day of this month) and (yesterday)
end ;
when I am running this code. I am getting 3706 syntax error:expected something in between field and '='.
How to fix this ?
A CASE statement will always return a value or NULL (if none of the conditions matches), so you can use it in your WHERE clause. There are a couple ways to format your CASE statement:
Format 1
CASE
WHEN <condition> THEN <some_expression>
WHEN <another_condition> THEN <another_expression>
ELSE <final_expression>
END
-- Example
CASE
WHEN col1 = 10 THEN 'Y'
WHEN col1 = 20 THEN 'N'
ELSE 'N/A'
END
Format 2
CASE <expression>
WHEN <value> THEN <expression>
WHEN <another_value> THEN <another_expression>
ELSE <final_expression>
END
-- Example
CASE col1
WHEN 10 THEN 'Y'
WHEN 20 THEN 'N'
ELSE 'NA'
END
I'm not sure what you're trying to do with your sample code, but it looks more like pseudo-code and will not work as-is. Your CASE statement is not formatted properly and your column references like column 1 will not work that way. If your column is actually named column 1, then you need to put double-quotes around it:
select * from table where "column 1" > 10
Can you please describe a little more clearly what exactly you are trying to do?
A CASE expression can't be used to create some kind of dynamic conditions. Write it as a bunch of AND/OR conditons:
select * from table
where
column 1 > 10 and
(
( column 2 = 1 and
(column 3<= 10 and column 4 between (1st day of prev month) and (prev month end) or column 5 = '8888-01-01')
)
or
column 4 between (1st day of this month) and (yesterday)
);
Double check the logic, the precedence of logical operators is
parenthesis
NOT
AND
OR

Sort numbers with 0 as the last priority, PL/SQL keyword for priority

I have:
PROCEDURE A
(
inId IN NUMBER,
RC1 OUT SYS_REFCURSOR
) IS
tMessage VARCHAR2(128);
BEGIN
OPEN RC1 FOR
SELECT * FROM
(
SELECT
a.company,
SUM(a.holding_balance) balance
FROM TableNameEntries A
WHERE
A.BATCH_ID = inId
GROUP BY a.company
)
ORDER BY balance DESC ;
EXCEPTION
WHEN OTHERS THEN
tMessage :='Exception ' || SQLCODE || ': ' || SQLERRM;
OPEN RC1 FOR
SELECT tMessage FROM DUAL;
END A;
For the balance column, I have values like -1, 0,1. Currently it's sorted like 1 0 -1, but I don't care about the zeros, so I want it to be like -1,1,0 or 1,-1,0
How do I do it in PL/SQL? I tried:
SELECT
a.company,
SUM(a.holding_balance) balance
FROM REC.CAG_GL_ENTRIES A
WHERE
A.BATCH_ID = 201311
order by case priority when 0 then 2 else 1 END priority
But it's saying PRIORITY is invalid identifier.
How can I get this to work?
Try:
ORDER BY CASE balance
WHEN 0 THEN null
ELSE balance
END
DESC NULLS LAST
there are two ways in your case (second is more common, first is more clear):
SELECT a.company,
SUM(a.holding_balance) balance
FROM REC.CAG_GL_ENTRIES A
WHERE A.BATCH_ID = 201311
order by abs(balance) desc;
SELECT a.company,
SUM(a.holding_balance) balance
FROM REC.CAG_GL_ENTRIES A
WHERE A.BATCH_ID = 201311
order by decode(balance,1,1,-1,1,2);
ORDER BY SIGN(ABS(balance)) DESC, balance
ABS() turns all the negatives to positives. SIGN() turns 0 to 0, >0 to 1 (and <0 to -1). Combined with DESC this puts all the zeros at the end and all the non-zeros above them in no particular order.
Then I sorted by the balance again to order the non-zeros.
You can also use
order by balance * balance desc

Error Message in a Case Statement

I have written the following statement which doesn't work because of the In clause i've added. Can someone help suggest a workable solution?
What I want to do is measure the min/max values of grades for each record key. Some have more than one grade so thats why I've added the In clause so it will factor this?
case when MIN("Grade - Current"."Grade Equivalency")=MIN("Grade - Current"."Grade Equivalency")
IN (People." Record Key") then 'y' else 'n' end
The data in the table looks like this:
RecordKey Version Grade
165 2009 1
165 2012 2
175 2009 1
189 2012 1
200 2009 2
200 2012 1
You already have a Boolean condition:
"MIN("Grade - Current"."Grade Equivalency")=MIN("Grade - Current"."Grade Equivalency")" in your when, so you cannot also do an IN clause too.
Also when you use the IN clause in the parenthesis you have to put values not table columns.
Maybe you need something like:
case
when MIN("Grade - Current"."Grade Equivalency")=MIN("Grade - Current"."Grade Equivalency") AND MIN("Grade - Current"."Grade Equivalency") IN (one or more values...) then 'y'
else 'n'
end
Second answer...
It's a little more complex, as it uses analytical functions.
Take a look below:
select RECORDKEY, VERSION_YEAR, GRADE,
case
when GRADE_PREV = 0 and GRADE_NEXT >= 0 then 'Stayed the same'
when GRADE_PREV = 0 and GRADE_NEXT > 0 then 'Stayed the same'
when GRADE_PREV > 0 and GRADE_PREV < GRADE then 'increased'
when GRADE_PREV > 0 and GRADE_PREV > GRADE then 'decreased'
else null
end as grade_change
from
(
select RECORDKEY, VERSION_YEAR, GRADE
,LAG(GRADE, 1, 0) over (partition by RECORDKEY order by RECORDKEY, VERSION_YEAR) as GRADE_PREV
,LEAD(GRADE, 1, 0) over (partition by RECORDKEY order by RECORDKEY, VERSION_YEAR) as GRADE_NEXT
from PLCH_GRADES
)
order by 1,2
Third answer...
Here it is, now integrating your "original" query:
select RECORDKEY, CALENDAR_YEAR, HEADCOUNT, GRADE,
case
when GRADE_PREV = 0 and GRADE_NEXT >= 0 then 'Stayed the same'
when GRADE_PREV = 0 and GRADE_NEXT > 0 then 'Stayed the same'
when GRADE_PREV > 0 and GRADE_PREV < GRADE then 'increased'
when GRADE_PREV > 0 and GRADE_PREV > GRADE then 'decreased'
else NULL
end as GRADE_CHANGE
from
(
select RECORDKEY, CALENDAR_YEAR, HEADCOUNT, GRADE
,LAG(GRADE, 1, 0) over (partition by RECORDKEY order by RECORDKEY, VERSION_YEAR) as GRADE_PREV
,LEAD(GRADE, 1, 0) over (partition by RECORDKEY order by RECORDKEY, VERSION_YEAR) as GRADE_NEXT
from
(
select
PEOPLE."Record Key" as RECORDKEY,
CALENDAR.year as CALENDAR_YEAR,
"Grade - Current"."Grade Equivalency" as GRADE,
"Fact - People".HEADCOUNT
from test
where location = 'NI'
and PEOPLE."Status Group" = 'CURRENT'
and PEOPLE."Headcount Marker" in ('Paid', 'Unpaid')
AND Calendar.Year IN ('2009', '2012')
)
)
order by 1,2

Resources