Need to create a case statement for multiple criteria with varchar and date data types, my code sp far:
select
least(coalesce(case when 1.other_id=10 then 1.datestr else 0 end,
case when 2.info='Yes' then 2.date else 0 end))as date1,
from
test1 as 1
left join test2 as 2 on 1.id = 2.id
I essentially want to get the lowest date between 2 conditions. Both conditions have some filters (other_id=10 in first, info="Yes" in second). For those conditions I want to compare least dates.
I think this is the logic:
select (case when 1.other_id = 10 and 2.info = 'Yes'
then least(case when 1.other_id=10 then 1.datestr end,
case when 2.info='Yes' then 2.date end
)
when 1.other_id = 10 then 1.date
else 2.date
end)
Or, you can use more appropriate default values in your expression. Something like this (it might depend on the database):
select least(case when 1.other_id = 10 then 1.datestr else '9999-01-01' end,
case when 2.info = 'Yes' then 2.date else '9999-01-01' end)
) as date1,
In My database I have a row with multiple Codes, EG:
ID,Code1,Code2,Code3,Code4
These codes reference a Procedure Name in another table EG:
Code1 = 'Procedure one'
Code2 = 'Procedure two'
ect.
I needed to convert this single row to show one line for every code, and corresponding procedure name EG:
ID,ProcedureName
1,'Procedure One'
1,'Procedure two'
2,'Procedure one'
To get this to work I'm using an outer join with an OR statement, not the most performance effective, but since the ProcedureName Table isn't that large, i'm not too fussed about overhead at the moment, more about getting it to work.
FROM Events EV
LEFT JOIN ProcedureName PN
ON (PN.CODE = Ev.Code1)
OR (PN.CODE = Ev.Code2)
OR (PN.CODE = Ev.Code3)
OR (PN.CODE = Ev.Code4)
This works, however Now I have the problem of being able to tell What procedure is the Primary, and Secondary. Usually the Primary/secondary is denoted purely by whatever one is in the first Code. IE the primary would be whatever is in Code1, secondary in code2, ect.
However since I have now Joined using an OR, i now have no idea what Code that the procedure has joined to.
I've thought of just doing a case statement
CASE
WHEN PN.CODE = Ev.Code1 THEN
'(Primary) ' + ISNULL(PN.NAME, '')
WHEN PN.CODE = Ev.Code2 THEN
'(Secondary) ' + ISNULL(PN.NAME, '')
WHEN PN.CODE = Ev.Code3 THEN
'(Tertiary) ' + ISNULL(PN.NAME, '')
WHEN PN.CODE = Ev.Code4 THEN
'(Quaternary) ' + ISNULL(PN.NAME, '')
END AS ProcedureName,
However this has the major issue of, on the off chance, that both code1 and code2 are the same code. Which means they will both show up as primary.
Can anyone give me any hints as to how to find out what the OR join actually Joined on? did it join on code1, code2? is there perhaps a better way to write the join that will allow me to have multiple lines per ID (depending on amount of codes) whilst still allowing me to find out where they are Code1 or code2?
I would reword the question slightly. In reality the it doesn't "join on a column", it joins on the result of a boolean expression.
So, what you want is to find out which parts of the boolean expression are true or not...
SELECT
*,
CASE WHEN PN.CODE = Ev.Code1 THEN 1 ELSE 0 END AS MatchingCode1,
CASE WHEN PN.CODE = Ev.Code2 THEN 1 ELSE 0 END AS MatchingCode2,
CASE WHEN PN.CODE = Ev.Code3 THEN 1 ELSE 0 END AS MatchingCode3,
CASE WHEN PN.CODE = Ev.Code4 THEN 1 ELSE 0 END AS MatchingCode4
FROM
Events EV
LEFT JOIN
ProcedureName PN
ON PN.CODE IN (Ev.Code1, Ev.Code2, Ev.Code3, Ev.Code4)
If you want that as a single column, you could use binary arithmetic.
SELECT
*,
CASE WHEN PN.CODE = Ev.Code1 THEN 1 ELSE 0 END +
CASE WHEN PN.CODE = Ev.Code2 THEN 2 ELSE 0 END +
CASE WHEN PN.CODE = Ev.Code3 THEN 4 ELSE 0 END +
CASE WHEN PN.CODE = Ev.Code4 THEN 8 ELSE 0 END AS MatchingCodes
FROM
Events EV
LEFT JOIN
ProcedureName PN
ON PN.CODE IN (Ev.Code1, Ev.Code2, Ev.Code3, Ev.Code4)
Here a value of 1 in MatchingCodes means that Code1 is a match. Similarly a value of 3 means Code1 and Code2 both match, or a value of 15 means that all the codes match.
EDIT: (After making it clear that you want multiple rows)
This is similar to Gordon's answer, but has slightly different behaviour; you get 1 row per match instead of 4 rows all the time, or one row with NULLs if there is no match.
SELECT
*
FROM
Events EV
OUTER APPLY
(
SELECT 1 AS MatchedCode, * FROM ProcedureName WHERE CODE = EV.Code1
UNION ALL
SELECT 2 AS MatchedCode, * FROM ProcedureName WHERE CODE = EV.Code2
UNION ALL
SELECT 3 AS MatchedCode, * FROM ProcedureName WHERE CODE = EV.Code3
UNION ALL
SELECT 4 AS MatchedCode, * FROM ProcedureName WHERE CODE = EV.Code4
)
PN
I think apply does what you want:
select e.id, v.which, v.code
from Events e cross apply
(values ('procedure1', code1), ('procedure2', code2), ('procedure3', code3), ('procedure4', code4)
) v(which, code)
If you want to filter out codes that are NULL, then add:
where v.code is null
I am looking for a DAX measure that is equal to If i have in SQL:
SELECT COUNT(NoDataValue WHEN -1 THEN 1 ELSE 0 END)
FROM
(
SELECT Employee.EmployeeID, CASE WHEN FACT.EmployeeID IS NULL
THEN -1
ELSE 1
END as NoDataValue
FROM Employee LEFT OUTER JOIN FACT
On Employee.EmployeeID = FACT.EmployeeID
) X
Essentially i want -1 when there is no data for an employee at the row level but when its aggregated i need count of NoDataValues (How many employees did not have data).
That is working fine at employee level with the measure i created
Annual Independence Compliance No Data:=
Var NoData=
SUM ( [NoDataValue] )
RETURN (IF (ISBLANK(NoData) , -1, NoData))
This looks like
But this is not aggregating the counts. I am having trouble of how to do that. This shows up as
I'm not sure if you SQL query is returning what you want but the query should look like below
SELECT SUM(case NoData WHEN -1 THEN 1 ELSE 0 END) as NoDataCount
FROM
(
SELECT Employee.EmployeeID, CASE WHEN FACT.EmployeeID IS NULL
THEN -1
ELSE 1
END as NoData
FROM Employee LEFT OUTER JOIN FACT
On Employee.EmployeeID = FACT.EmployeeID
) X
or
SELECT SUM(IIF(NoData = -1,1,0)) as NoDataCount
I'm using proc sql, and using multiple case when statements to add columns with either a 0 or 1 if the condition is met. It's a big bottleneck right now since it has to scan through each id for each case when statement. So I'm trying to figure out a way to somehow nest the case statements to perform each iteration, instead of having to iterate for all case statements.
This is an example of my code that is taking too long right now.
SELECT *,
CASE WHEN loannumber IN (
SELECT loannumber FROM PREPAY_LOAN_IDS
) THEN 1
ELSE 0 END AS PREPAY_FLAG,
CASE WHEN loannumber IN (
SELECT loannumber FROM DPD_30_IDS
) THEN 1
ELSE 0 END AS DPD_30_FLAG,
CASE WHEN loannumber IN (
SELECT loannumber FROM DPD_60_IDS
) THEN 1
ELSE 0 END AS DPD_60_FLAG,
CASE WHEN loannumber IN (
SELECT loannumber FROM DPD_90_IDS
) THEN 1
ELSE 0 END AS DPD_90_FLAG,
CASE WHEN loannumber IN (
SELECT loannumber FROM DPD_120_IDS
) THEN 1
ELSE 0 END AS DPD_120_FLAG,
CASE WHEN loannumber IN (
SELECT loannumber FROM FORECLOSURE_IDS
) THEN 1
ELSE 0 END AS FORECLOSURE_FLAG
FROM(
SELECT *
FROM MORTGAGES
)
The below query will work faster than the one you have posted as the input table is not completely access to retrieve the results. Try running this query and see how it performs.
SELECT M.*,
CASE WHEN PLI.loannumber IS NOT NULL THEN 1
ELSE 0 END AS PREPAY_FLAG,
CASE WHEN D3I.loannumber IS NOT NULL THEN 1
ELSE 0 END AS DPD_30_FLAG,
CASE WHEN D6I.loannumber IS NOT NULL THEN 1
ELSE 0 END AS DPD_60_FLAG,
CASE WHEN D9I.loannumber IS NOT NULL THEN 1
ELSE 0 END AS DPD_90_FLAG,
CASE WHEN D12I.loannumber IS NOT NULL THEN 1
ELSE 0 END AS DPD_120_FLAG,
CASE WHEN FCI.loannumber IS NOT NULL THEN 1
ELSE 0 END AS FORECLOSURE_FLAG
FROM MORTGAGES M
LEFT JOIN
PREPAY_LOAN_IDS PLI
ON M.loannumber = PLI.loannumber
LEFT JOIN
DPD_30_IDS D3I
ON M.loannumber = D3I.loannumber
LEFT JOIN
DPD_30_IDS D6I
ON M.loannumber = D6I.loannumber
LEFT JOIN
DPD_90_IDS D9I
ON M.loannumber = D9I.loannumber
LEFT JOIN
DPD_90_IDS D12I
ON M.loannumber = D12I.loannumber
LEFT JOIN
FORECLOSURE_IDS FCI
ON M.loannumber = FCI.loannumber
;
Since you're using SAS, here's a data step alternative, assuming that each of your datasets is already either sorted by or has an index on loannumber:
data want;
merge MORTGAGES(in = Mortgages)
PREPAY_LOAN_IDS(in = PLIDs keep = loannumber)
/*etc*/
;
by loannumber;
if Mortgages;
PREPAY_FLAG = PLIDs;
/*etc*/
run;
N.B. You will get duplicated records from MORTGAGES if you have duplicates in any of your other tables.
given the following table definition
I have a query written as so:
select id,
(
case
when partial >= 2 and full >=2
then sum(partial+full)
when partial >=2
then partial
when full >= 2
then full
else 0
end
) counts
from Foo
What is the minimum number of checks that I have to do to ensure that the inner when clauses:
partial>=2 and full >=2 are not invoked twice. That is does the case when/then syntax treat everything as else ifs and not just straight ifs?
You can do
select id,
(
case when partial >= 2 then partial else 0 end +
case when full >= 2 then full else 0 end
) counts
from Foo
Sample SQL FIDDLE