Using Nested Case Expression - sql

I am stuck in properly using Nested Case Expression.
The requirement is to create the calculated column that will be either 0 or 1.
If the name is 'abc' and ind = 1, then the value of calc column will be 1 . But if the name is 'abc' and salary is > 2000 . then the value will be 1 again irrespective the value of ind.
I have written the below query using OR condition in CASE Expression but want to use the Nested CASE.
select t.*, case when (name = 'abc' and ind = 1 ) or (name = 'abc' and sal > 2000)
then 1
else 0
end
from test t
Below is the result:

You don't need nested CASE:
-- multiple conditions
select t.*, case when name = 'abc' and ind = 1 then 1
when name = 'abc' and sal > 2000 then 1
else 0 end
from test t

I don't know why you need nested case expression, i would do instead of nested case expression that would be more efficient :
select t.*, (case when name = 'abc' and (ind = 1 or sal > 2000)
then 1
else 0
end)
from test t;

If you HAVE to have nested case expression then this is how you would write it:
SELECT t.*,
CASE
WHEN name = 'abc' THEN
CASE
WHEN ind = 1 THEN 1
WHEN sal > 2000 THEN 1
ELSE 0
END
ELSE 0
END
FROM test t;

If you are on SQL Server 2012 and above, you can also use an IIF statement like below:
select iif(name = 'abc' AND (salary > 2000 OR ind = 1), 1,0)

Related

Sql query to create following tables

use the below table 1 to generate table 2
Table 1
Col1 A B C
------------------
N1 1 0 0
N2 0 1 0
N3 1 0 0
Table 2
output
new_col
-------
N1 A
N2 B
N3 A
Also how to use Table 2 to generate table 1 above
Following SQL query can be help to get requested output:
SELECT Col1,IF(A=1,'A',IF(B=1,'B','C')) AS result FROM `table_name`;
You can use conditinal with CONCAT() Function :
SELECT CONCAT(col1,' ',
CASE WHEN A = 1 THEN 'A' ELSE '' END,
CASE WHEN B = 1 THEN 'B' ELSE '' END,
CASE WHEN C = 1 THEN 'C' ELSE '' END)
FROM table1
provided you're on a DBMS with brand name such as MySQL, PostGRES, SQL Server. As an example, Oracle DB won't allow using more than two arguments for CONCAT() Function.
In order to create table2, use for most of the DBMS :
CREATE TABLE table2 AS
SELECT CONCAT(col1,' ',
CASE WHEN A = 1 THEN 'A' ELSE '' END,
CASE WHEN B = 1 THEN 'B' ELSE '' END,
CASE WHEN C = 1 THEN 'C' ELSE '' END) AS new_col
FROM table1
except for SQL Server in which prefer using :
SELECT CONCAT(col1,' ',
CASE WHEN A = 1 THEN 'A' ELSE '' END,
CASE WHEN B = 1 THEN 'B' ELSE '' END,
CASE WHEN C = 1 THEN 'C' ELSE '' END) AS new_col
INTO table2
FROM table1
In order to implement a reverse engineering(go back to original table), you need to consider the dialectics for each seperate database to handle string values. Assume you're using MySQL DB, then consider using :
CREATE TABLE table3 AS
SELECT SUBSTRING(new_col,1,instr(new_col,' ')-1) AS col1,
CASE WHEN instr(new_col,'A') > 0 THEN 1 ELSE 0 END AS A,
CASE WHEN instr(new_col,'B') > 0 THEN 1 ELSE 0 END AS B,
CASE WHEN instr(new_col,'C') > 0 THEN 1 ELSE 0 END AS C
FROM table2
where I used a different table name (table3), since table1 already exists.
Demo
Btw, if Oracle DB is the case, then use :
SELECT CONCAT(CONCAT(col1,' '),
CASE WHEN A = 1 THEN 'A' ELSE '' END||
CASE WHEN B = 1 THEN 'B' ELSE '' END||
CASE WHEN C = 1 THEN 'C' ELSE '' END) AS new_col
FROM table1
You can use one case statement. This works in Oracle.
SELECT col1
|| CASE
WHEN A = 1
THEN 'A'
WHEN B = 1
THEN 'B'
WHEN C = 1
THEN 'C'
END
NEW_COL
FROM table1
It is unclear what you want when there are multiple "1"s in a row. This is a simple solution:
select id, A from t where A = 1
union all
select id, B from t where B = 1
union all
select id, C from t where C = 1;
In databases that support lateral joins, I would recommend:
select t.id, v.which
from t cross join lateral
(values ('A', t.A), ('B', B), ('C', C)
) v(which, val)
where val = 1;

SQL AS query results in duplicate column

I have a SQL query like so
SELECT
name,
CASE WHEN (new_value=2) THEN 0 END as out,
CASE WHEN (previous_value=2) THEN 1 END as out
FROM my_table;
This results in duplicate columns:
name out out
foo 1 null
bar null 1
instead of
name out
foo 1
bar 0
How do I fix this?
You want one case expression with two conditions:
SELECT name,
(CASE WHEN new_value = 2 THEN 0
WHEN previous_value = 2 THEN 1
END) as out
FROM my_table;
Consider:
SELECT
name,
CASE
WHEN new_value = 2 THEN 0
WHEN previous_value = 2 THEN 1
END as out
FROM my_table;
In your query, each case expression generates one column in the resulset. You want only one, with two branches (denoted by when ... then ...)
You are getting null output, so you need to add else on this.
select name,
case
when new_value = 2 then 0
when previous_value = 2 then 1
else 0 end as out
from my_table;

SQL Server - Get column who have specific value

I have a SQL query which returns :
id | value
1 a
1 a
1 b
2 a
2 a
I want to get only id who have only the value a. So the id 2
How to do this ?
You can use aggregation and having clause to check if all the rows have value 'a' for a given id:
Using Count:
select id
from t
group by id
having count(*) = count(case when value = 'a' then 1 end);
Or using Sum
select id
from t
group by id
having SUM(case when value = 'a' then 0 else 1 end) = 0;
Use the next code:-
Select id
from #test
group by id
having sum (case when value = 'a' then 0 else 1 end) = 0
The clue is passing 0 for 'a' and pass 1 for other, then having sum equals 0
This is slightly slower than #Gurwinder Singh's answer but can be more readable if performance is not your top priority.
CREATE TABLE tmp (id int, [value] char(1))
INSERT INTO tmp values (1,'a'),(1,'a'),(1,'b'),(2,'a'),(2,'a')
SELECT DISTINCT id
FROM tmp a
WHERE [value] = 'a'
AND id NOT IN (
SELECT id FROM tmp
WHERE [value] <> 'a')

Require help on Inner join query on single table

I have single table called TEST as follow :
job_id input_id match_outcome
101 1 MATCH
101 2 NO_MATCH
201 1 NO_MATCH
201 2 MATCH
Expected outcome:
job_id input_id match_outcome
201 1 NO_MATCH
101 2 NO_MATCH
Query I used:
select *
from ( select * from TEST where job_id = '101') q1 join
(select * from TEST where job_id = '201') q2
where q1.match_outcome= 'MATCH' and q2.match_outcome= 'NO_MATCH' OR
q2.match_outcome= 'MATCH' and q1.match_outcome= 'NO_MATCH'
Overall objective:
I need input_id and other data which is MATCH with one job_id and and the input id which is NO MATCH in another set of job id.But this query takes longer times since these table contains millions of record and I didn't see the outcome yet.(Fyi, I am using hive tables) any efficient or any different better way to don this!! Thanks
If I try to understand this: "I need input_id . . . which is MATCH with one job_id and and the input id which is NO MATCH in another set of job id", then you can use aggregation:
select input_id
from text
group by input_id
having sum(case when match_outcome = 'MATCH' then 1 else 0 end) > 0 and
sum(case when match_outcome = 'NO MATCH' then 1 else 0 end) > 0;
This assumes that input_id is not duplicated for a give job_id, which seems consistent with the data in the question.
If you want the original data row, then you can join this into the query:
select t.*
from test t join
(select input_id
from text
group by input_id
having sum(case when match_outcome = 'MATCH' then 1 else 0 end) > 0 and
sum(case when match_outcome = 'NO MATCH' then 1 else 0 end) > 0
) i
on t.input_id = i.input_id;
Select * from TEST
Where match_outcome='NO_MATCH'

Returning 1 or 0 in specific SQL query

I have three columns in the table MYTABLE (ID, NUM, NAMES). There is a column NAMES. I need to check on NAMES column to see if the first name is JACK or BRUCE and the corresponding NUM column = 0. If the match is found, return 1 else 0.
ID NUM NAMES
1 1 'TOM'
2 1 'MIKE'
3 0 'JACK'
4 1 'MICKY'
5 0 'BRUCE'
I've came up with the following query:
select *
case NAMES in ('JACK', 'BRUCE') and NUM=0 then 1 else 0 end as MYNAMES
from MYTABLE;
That does not work unfortunately.
This works (SQLFiddle demo):
SELECT id, num,
CASE WHEN names IN ('JACK', 'BRUCE') AND num=0
THEN 1 ELSE 0 END AS mynames
FROM mytable
select case
when exists
(
select *
from YourTable
where name in ('JACK', 'BRUCE')
and NUM = 0
)
then 1
else 0
end
from dual
Live example at SQL Fiddle.
select case when NAMES in ('JACK','BRUCE') AND NUM = 0
then 1
else 0
end
from your_table