Use of CASE with criteria from multiple tables - sql

I have to do a select query to create a view with specific criteria.
I have multiple tables which contains many many columns and lines.
However, I have extracted a value to use as my key (e.g.: id). I have 7000+ of those unique keys that I extracted from all my tables with the function UNION to avoid duplicates.
Now, I want to add a column INDICATOR_1 which will affect the value YES or NO based on criteria.
This is where I struggle.
I need to find the line in those tables that contain the id. After that, I'd like to check, always in that line, if the field XYZ contains the value 'N' (example). If yes, affect the value 'YES' to INDICATOR_1, else it's no.
In a matter of pseudo-code, what I want to do looks like this :
CASE
WHEN id = (id from table_1) AND (if table_1.xyz = 'N')
THEN 'YES'
ELSE 'NO'
END AS INDICATOR_1
I don't know if I'm clear enough, but your help will be greatly appreciated.

If I understand correctly, you want a separate indicator for each table. Something like this:
select i.*,
(case when exists (select 1
from table1 t1
where t1.id = i.id and t1.xyz = 'N'
)
then 'YES' else 'NO'
end) as indicator_1,
(case when exists (select 1
from table2 t2
where t2.id = i.id and t2.xyz = 'N'
)
then 'YES' else 'NO'
end) as indicator_2,
. . .
from (<your id list here>) i

I think you should fix this in the union, where you have all the data you need. You probably have something like:
SELECT Id
FROM table_1
UNION
SELECT Id
FROM table_2
How about selecting the information you want as well (I use distinct here to clarify):
SELECT DISTINCT Id
, CASE WHEN table_1.xyz = 'N' THEN 'N'
ELSE 'Y'
END INDICATOR_1
FROM table_1
This can lead to more records than you had, if id's can have records of both flavours exist. We can fix that with a row number in an outer query. You end up with something like:
SELECT Id
, INDICATOR_1
FROM (
SELECT Id
, INDICATOR_1
, ROW_NUMBER()OVER(PARTITION BY ID ORDER BY CASE WHEN INDICATOR_1 ='N' THEN 0 ELSE 1 END) RN
FROM (
SELECT Id
, CASE WHEN table_1.xyz = 'N' THEN 'N'
ELSE 'Y'
END INDICATOR_1
FROM table_1
UNION
...
) T
) S
WHERE S.RN = 1
You can in fact shorten that by using the inner most case expression in the ROW_NUMBER expression.

Related

SQL using a function to check existence of event over a user id?

I have a table 'EVENTS' with a user column, and an 'event' column
User
Event
1
a
1
a
1
a
1
b
2
b
2
c
In the above example, user 1 has never had event c appear for them. I want to do something like
WITH table_a as (
SELECT
CASE WHEN EVENT = 'c' Then 'Y' ELSE 'n' end as event_occured,
user_id
FROM EVENTS)
and then get a result such as
User
is_occured
1
n
2
y
So I first tried to do it like such
SELECT DISTINCT USER,'y' is_occured FROM table_a WHERE event_occured='y'
UNION
SELECT DISTINCT USER,'n' is_occured FROM table_a WHERE event_occured='n'
But this is obviously a bit clunky, and will be unmanageable, especially as more columns are added to the event table, and needed in the query. so next I tried to do it using a window function, but I'm not certain how to pull the values into only singular users, where I'm only looking for the existence.
SELECT user,
CASE WHEN ... over(partion by user)
FROM EVENTS
But I'm very confused how to procede or if this is even the right track
If you are purely trying to get a Y or N onto these, you can do a simple MAX with a case expression:
select [User]
, MAX(case when [Event] = 'c' then 'Y' else 'N' end) is_occurred
from [EVENTS]
group by [User]
If you wanted to avoid group by, you could do a window function:
select distinct [User]
, MAX(case when [Event] = 'c' then 'Y' else 'N' end) over (partition by [User])
from [EVENTS]
If you wanted to have this as a function, you could parameterize the [Event] comparison and pass the user as well to something like:
select MAX(case when [Event] = #p_checked_event then 'Y' else 'N' end)
from [EVENTS]
where [User] = #p_checked_user
Return the results of that query, and call it like:
select distinct [User]
, CheckEventOccurred([User], 'c')
from [EVENTS]

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.

Joining a Temp Table to Actual Table

I need to verify that each order has been acknowledged. The problem is that each order can have multiple codes. The query I had (utilizing a CASE statement) would check for blank fields or fields with the string "None" to verify the order has not been acknowledged. It would return the appropriate result, but multiple rows (once for each possible response) and I only need (1).
I'm attempting to create a temp table that will return the appropriate result and join (via an order unique ID) the two tables together hoping to correct the multiple row issue. Here is the code:
DROP TABLE staging_TABLE;
CREATE TEMP TABLE staging_TABLE(
ORDERID varchar(256) ,
CODE varchar(256) );
/*Keeping data types consistent with the real table*/
INSERT INTO staging_TABLE
SELECT ORDERID,
CASE CODE
WHEN 'None' THEN 'No'
WHEN '' THEN 'No'
ELSE 'Yes'
END
FROM ORDERS
WHERE UTCDATE > SYSDATE - 10
AND CODE IS NOT NULL;
SELECT R.QUESTION,
R.ORDERNAME,
T.CODE
FROM ORDERS R
INNER JOIN staging_TABLE T
ON R.ORDERID= T.ORDERID
WHERE R.UTCDATE > SYSDATE - 10
AND R.CODE IS NOT NULL
AND R.CATEGORY IS NOT NULL
AND R.UTCDATE IS NOT NULL
GROUP BY
R.ORDER,
T.CODE,
R.ORDERNAME,
R.CODE
ORDER BY
R.ORDERNAME,
R.ORDER;
Am I doing this correctly? Or is this even the right approach?
Am I doing this correctly? Or is this even the right approach?
No. You don't need a temp table for this. Your query might look like this:
SELECT question, ordername
, CASE WHEN code IN ('None', '') THEN 'No' ELSE 'Yes' END AS code
FROM orders
WHERE utcdate > sysdate - 10
AND code IS NOT NULL
AND category IS NOT NULL
GROUP BY question, ordername, 3, "order"
ORDER BY ordername, "order";
ORDER is a reserved word. It's not possible to use it as column name unless double quoted. There is something wrong there.
AND R.UTCDATE IS NOT NULL is redundant. It can't be NULL anyway with WHERE R.UTCDATE > SYSDATE - 10
3 in my GROUP BY clause is a positional reference to the CASE expression. Alternatively you can spell it out again:
....
GROUP BY question, ordername
, CASE WHEN code IN ('None', '') THEN 'No' ELSE 'Yes' END
, "order"
You can use the DISTINCT keyword as follows so you will not need a temp table:
SELECT DISTINCT QUESTION,
ORDERNAME,
CASE CODE
WHEN 'None' THEN 'No'
WHEN '' THEN 'No'
ELSE 'Yes'
FROM ORDERS
WHERE UTCDATE > SYSDATE - 10
AND CODE IS NOT NULL
AND CATEGORY IS NOT NULL
AND UTCDATE IS NOT NULL
ORDER BY 2,3;

If at least one record has value 1 then return 'Yes'

I have a table in SQL Server that contains a column yesno.
If at least one of the rows has the column yesno=1 then I need to return only one row yes.
I made a query that returns for every row if is yes or no.
(select (case when isnull(coalesce(dl.yesno,'2'),'2')='1' then 'Yes' else 'NO' END)
from table dl where dl.ID='A5454322-C239-4FF2-A458-8A9BD79C1839')
select 'yes'
where exists (select 1 from the_table where yesno = '1');
SQLfiddle example: http://sqlfiddle.com/#!3/069204/1
select 'yes' where exists (select * from MyTable where [yesno]='1')
select top 1 'yes' from table where yesno = 1

SQL using CASE in SELECT with GROUP BY. Need CASE-value but get row-value

so basicially there is 1 question and 1 problem:
1. question - when I have like 100 columns in a table(and no key or uindex is set) and I want to join or subselect that table with itself, do I really have to write out every column name?
2. problem - the example below shows the 1. question and my actual SQL-statement problem
Example:
A.FIELD1,
(SELECT CASE WHEN B.FIELD2 = 1 THEN B.FIELD3 ELSE null FROM TABLE B WHERE A.* = B.*) AS CASEFIELD1
(SELECT CASE WHEN B.FIELD2 = 2 THEN B.FIELD4 ELSE null FROM TABLE B WHERE A.* = B.*) AS CASEFIELD2
FROM TABLE A
GROUP BY A.FIELD1
The story is: if I don't put the CASE into its own select statement then I have to put the actual rowname into the GROUP BY and the GROUP BY doesn't group the NULL-value from the CASE but the actual value from the row. And because of that I would have to either join or subselect with all columns, since there is no key and no uindex, or somehow find another solution.
DBServer is DB2.
So now to describing it just with words and no SQL:
I have "order items" which can be divided into "ZD" and "EK" (1 = ZD, 2 = EK) and can be grouped by "distributor". Even though "order items" can have one of two different "departements"(ZD, EK), the fields/rows for "ZD" and "EK" are always both filled. I need the grouping to consider the "departement" and only if the designated "departement" (ZD or EK) is changing, then I want a new group to be created.
SELECT
(CASE WHEN TABLE.DEPARTEMENT = 1 THEN TABLE.ZD ELSE null END) AS ZD,
(CASE WHEN TABLE.DEPARTEMENT = 2 THEN TABLE.EK ELSE null END) AS EK,
TABLE.DISTRIBUTOR,
sum(TABLE.SOMETHING) AS SOMETHING,
FROM TABLE
GROUP BY
ZD
EK
TABLE.DISTRIBUTOR
TABLE.DEPARTEMENT
This here worked in the SELECT and ZD, EK in the GROUP BY. Only problem was, even if EK was not the designated DEPARTEMENT, it still opened a new group if it changed, because he was using the real EK value and not the NULL from the CASE, as I was already explaining up top.
And here ladies and gentleman is the solution to the problem:
SELECT
(CASE WHEN TABLE.DEPARTEMENT = 1 THEN TABLE.ZD ELSE null END) AS ZD,
(CASE WHEN TABLE.DEPARTEMENT = 2 THEN TABLE.EK ELSE null END) AS EK,
TABLE.DISTRIBUTOR,
sum(TABLE.SOMETHING) AS SOMETHING,
FROM TABLE
GROUP BY
(CASE WHEN TABLE.DEPARTEMENT = 1 THEN TABLE.ZD ELSE null END),
(CASE WHEN TABLE.DEPARTEMENT = 2 THEN TABLE.EK ELSE null END),
TABLE.DISTRIBUTOR,
TABLE.DEPARTEMENT
#t-clausen.dk: Thank you!
#others: ...
Actually there is a wildcard equality test.
I am not sure why you would group by field1, that would seem impossible in your example. I tried to fit it into your question:
SELECT FIELD1,
CASE WHEN FIELD2 = 1 THEN FIELD3 END AS CASEFIELD1,
CASE WHEN FIELD2 = 2 THEN FIELD4 END AS CASEFIELD2
FROM
(
SELECT * FROM A
INTERSECT
SELECT * FROM B
) C
UNION -- results in a distinct
SELECT
A.FIELD1,
null,
null
FROM
(
SELECT * FROM A
EXCEPT
SELECT * FROM B
) C
This will fail for datatypes that are not comparable
No, there's no wildcard equality test. You'd have to list every field you want tested individually. If you don't want to test each individual field, you could use a hack such as concatenating all the fields, e.g.
WHERE (a.foo + a.bar + a.baz) = (b.foo + b.bar + b.az)
but either way, you're listing all of the fields.
I might tend to solve it something like this
WITH q as
(SELECT
Department
, (CASE WHEN DEPARTEMENT = 1 THEN ZD
WHEN DEPARTEMENT = 2 THEN EK
ELSE null
END) AS GRP
, DISTRIBUTOR
, SOMETHING
FROM mytable
)
SELECT
Department
, Grp
, Distributor
, sum(SOMETHING) AS SumTHING
FROM q
GROUP BY
DEPARTEMENT
, GRP
, DISTRIBUTOR
If you need to find all rows in TableA that match in TableB, how about INTERSECT or INTERSECT DISTINCT?
select * from A
INTERSECT DISTINCT
select * from B
However, if you only want rows from A where the entire row matches the values in a row from B, then why does your sample code take some values from A and others from B? If the row matches on all columns, then that would seem pointless. (Perhaps your question could be explained a bit more fully?)