SQL Server - What's the right query for this purpose? - sql-server

I have a TABLE that contains, for example:
ID CVG
4 A
4 C
5 B
Each row contains a coverage for a given ID. If the ID does not have a coverage, there will be no row in the table (ex. ID 4 has no coverage B).
From this table I want to write a query like
SELECT ID, A = case (when ??? then 'TRUE' when ??? then 'FALSE'), B = case (...), C = case (...) FROM TABLE
that will give the output
ID A B C
4 TRUE FALSE TRUE
5 FALSE TRUE FALSE
where there is only one row for each ID, and one column for each coverage.
What's a workable query for this? I'm not allowed to change any permanent tables on the server so I'm trying to reach a solution with what I have.

You can use conditional aggregation to get the required result:
SELECT ID,
CASE
WHEN COUNT(CASE WHEN CVG = 'A' THEN 1 END)>=1 THEN 'TRUE'
ELSE 'FALSE'
END AS A,
CASE
WHEN COUNT(CASE WHEN CVG = 'B' THEN 1 END)>=1 THEN 'TRUE'
ELSE 'FALSE'
END AS B,
CASE
WHEN COUNT(CASE WHEN CVG = 'C' THEN 1 END)>=1 THEN 'TRUE'
ELSE 'FALSE'
END AS C,
.... etc
FROM mytable
GROUP BY ID
SQL Fiddle Demo

You could do something like this:
select
ID,
max(case when CVG = 'A' then 'TRUE' else 'FALSE' end),
max(case when CVG = 'B' then 'TRUE' else 'FALSE' end),
max(case when CVG = 'C' then 'TRUE' else 'FALSE' end),
from
table
group by
ID
The case + max will select the true if even one row is found for that ID, otherwise false.

If you want to have it select where
A = case (when ??? then 'TRUE' when ??? then 'FALSE'), B = case (...), C = case (...)
which is what I got from your explenation, what you need to do is
SELECT id, A, B, C FROM TABLE WHERE A = case (when ??? then 'TRUE' when ??? then 'FALSE'), B = case (...), C = case (...)

Related

Parsing JSON value in a Snowflake Variant column to multiple columns based on condition

I am trying to parse below JSON data in column test_column from table table_a. If the label department has Electrical, dept_1 should be defaulted as 1, if label department has Electronics, dept_2 should be defaulted to 1, and if label department has Chemical, dept_3 should be defaulted to 1.
test_column
{"labels": {"department_id": "1","department": ["Electrical","Electronics","Chemical"]}}
{"labels": {"department_id": "2","department": ["Electrical"]}}
I used below query but it is not yielding what i want -
Query used:
select dept_id,
case when dept='Electrical' then 1 else NULL end as dep1,
case when dept='Electronics' then 2 else NULL end as dep2,
case when dept='Chemical' then 3 else NULL end as dep3
from(
SELECT
test_column:labels:department_id::varchar as dept_id,
array_to_string(test_column:labels:department,',') as dept
FROM table_a
);
Could you tell me what is going wrong? Am getting NULL for records having all 3 Eletrical, Eletronics, and Chemical.
Expected result:
dept_id
dept_1
dept_2
dept_3
1
1
1
1
2
1
NULL
NULL
You have 2 options to do this differently.
Option #1: Flatten your array and then re-aggregate back for your case statements:
WITH x AS (
SELECT parse_json('{"labels": {"department_id": "1","department": ["Electrical","Electronics","Chemical"]}}') as var
)
SELECT x.var:labels:department_id::integer as dept_id,
max(case when y.value::varchar='Electrical' then 1 else NULL end) as dep1,
max(case when y.value::varchar='Electronics' then 2 else NULL end) as dep2,
max(case when y.value::varchar='Chemical' then 3 else NULL end) as dep3
FROM x,
lateral flatten (input=>var:labels:department) y
group by 1;
Option #2 - since your case statement is just evaluating the presence of a value, you can just look at the array using a ARRAY_CONTAINS function to evaluate:
WITH x AS (
SELECT parse_json('{"labels": {"department_id": "1","department": ["Electrical","Electronics","Chemical"]}}') as var
)
SELECT x.var:labels:department_id::integer as dept_id,
case when array_contains('Electrical'::variant, var:labels:department::array) then 1 else NULL end as dep1,
case when array_contains('Electronics'::variant, var:labels:department::array) then 2 else NULL end as dep2,
case when array_contains('Chemical'::variant, var:labels:department::array) then 3 else NULL end as dep3
FROM x;
Please try the below query:
SELECT
test_column:labels:department_id::varchar as dept_id,
IFF(ARRAY_CONTAINS('Electrical'::VARIANT, test_column:labels:department), 1, NULL) as DEP_1,
IFF(ARRAY_CONTAINS('Electronics'::VARIANT, test_column:labels:department), 1, NULL) as DEP_2,
IFF(ARRAY_CONTAINS('Chemical'::VARIANT, test_column:labels:department), 1, NULL) as DEP_3
FROM table_a;

Case with multiple conditions on multiple columns

I am trying to figure out how to make this work:
CASE
WHEN a.val IS NULL AND (a.CreatedBy <> 'MDI' OR a.Type <> 'RO' OR a.Unit <> 'ER') THEN 1
ELSE 0
END as field_name
Basically I am looking for rows where a.val is null, but ignore the row if any of these columns (a.CreatedBy or a.Type or a.Unit) have a specific value. Even if one of these columns is true for the specific value the case should return 0.
Is it possible? Thanks in advance.
You will need AND instead of OR operators.
CASE WHEN a.val IS NULL
AND a.CreatedBy <> 'MDI'
AND a.Type <> 'RO'
AND a.Unit <> 'ER'
THEN 1
ELSE 0
END as field_name
CASE WHEN A.VAL IS NULL AND
(A.CREATED_BY<>'MDI' OR A.TYPE<>'RO','AND A.UNIT<>'ER') THEN 1
ELSE 0 END
AS COLUMNNAME

SQL: Reusing Query with EXIST

Ok so I have a query that looks something like
SELECT
CASE WHEN EXISTS(SELECT NULL
FROM B
WHERE B.LENGTH = A.LENGTH + 10)
THEN 'Yes'
ELSE 'No'
END AS Result1,
CASE WHEN EXISTS(SELECT NULL
FROM B
WHERE B.LENGTH = A.LENGTH - 10)
THEN 'Yes'
ELSE 'No'
END AS Result2,
CASE WHEN EXISTS(SELECT NULL
FROM B
WHERE B.LENGTH = A.LENGTH)
THEN 'Yes'
ELSE 'No'
END AS Result3
FROM A
As you can see the 3 EXIST Queries are almost the same with little differentce that (I hope) can be passed as an argument.
I tried to create a TVF but it fails when I Return SELECT NULL... but works if I use SELECT *. The thing I am afraid of is that I don't need the values I want to check if only exists and that's it.
My question is what would be the best way to refactor this code so it's not that repetitive?
You can use conditional aggregation to generate one query per row having three columns:
SELECT CASE WHEN CA.C1 > 0 THEN 'Yes' ELSE 'No' END
, CASE WHEN CA.C2 > 0 THEN 'Yes' ELSE 'No' END
, CASE WHEN CA.C3 > 0 THEN 'Yes' ELSE 'No' END
FROM A
CROSS APPLY (
SELECT COUNT(CASE WHEN B.LENGTH = A.LENGTH + 10 THEN 1 END)
, COUNT(CASE WHEN B.LENGTH = A.LENGTH - 10 THEN 1 END)
, COUNT(CASE WHEN B.LENGTH = A.LENGTH THEN 1 END)
FROM B
WHERE B.LENGTH IN (A.LENGTH + 10, A.LENGTH - 10, A.LENGTH)
) AS CA(C1, C2, C3)
You could do something like this:
SELECT A.Length,
CASE COUNT(CASE A.[LENGTH] WHEN B.[LENGTH] - 10 THEN 1 END)WHEN 0 THEN 'No' ELSE 'Yes' END AS result1,
CASE COUNT(CASE A.[LENGTH] WHEN B.[LENGTH] + 10 THEN 1 END)WHEN 0 THEN 'No' ELSE 'Yes' END AS result2,
CASE COUNT(CASE A.[LENGTH] WHEN B.[LENGTH] THEN 1 END)WHEN 0 THEN 'No' ELSE 'Yes' END AS result3
FROM A
CROSS JOIN B
GROUP BY A.Length;
This saves on 3 scans of the table B, but you will still need repetitive logic of some kind.

SQL Query for CASE Statement

I have two table one is master table and another table is you can select item from first table.
MasterTable
ItemID ItemName
1 Football
2 Cricket
3 Badminton
SelectionTable
UserID SelectedItemId
1 2
1 3
2 1
OutPut
UserId SelectedItemID SelectionStatus
1 1 False
1 2 True
1 3 True
Query
SELECT S.UserId,M.ItemID,
CASE M.ItemID
WHEN 1 Then 'True'
WHEN 2 Then 'True'
WHen 3 Then 'True' END AS SelectionStatus
From MasterTable M
JOIN SelectionTable S ON S.SelectedItemID=M.ItemID
WHERE S.UserId=1
If no any item selected then all are false.I don't know how to do.
Assuming that you have a User table, you can get the status of every user / item combination by querying cartesean product (cross join).
The status True or False can be determined the presence or absence of a corresponding record in the SelectionTable.
select
u.UserId,
m.ItemId,
case
when exists
(select *
from SelectionTable s
where s.UserId = u.UserId
and s.SelectedItemId = m.ItemId)
then 'True'
else 'False'
end
from MasterTable m, User u
This technique can be applied to the single user case (UserId equals 1) as follows:
select
m.ItemId,
case
when exists
(select *
from SelectionTable s
where s.UserId = 1
and s.SelectedItemId = m.ItemId)
then 'True'
else 'False'
end
from MasterTable m
You can use else and a left join from SelectionTable to MasterTable.
SELECT S.UserId,M.ItemID,
CASE M.ItemID
WHEN 1 Then 'True'
WHEN 2 Then 'True'
WHen 3 Then 'True'
else 'False'
END AS SelectionStatus
From SelectionTable S
left JOIN MasterTable M ON S.SelectedItemID=M.ItemID
WHERE S.UserId=1

How do I use this condition inside CASE WHEN?

I want if Status column = 1
Check If there are rows in another table return 'Check' and If no rows return 'In DB'
SELECT ID, UserName,
CASE [Status]
WHEN 1 THEN
if ((Select Count(*) From Logs_TB Where Logs_TB.UserName = Users_TB.UserName) > 0)
'Check'
Else
'In DB'
WHEN 2 THEN 'Revision'
WHEN 3 THEN 'Sent'
END AS StatusName
FROM Users_TB CROSS JOIN Logs_TB
Edit 1:
I have Two Tables
in First Table.
I want to get the following result for Column [Status]
if FirstTable.ColumnStatus = 1
if SecondTable.ColumnA = FirstTable.ColumnB Has Rows
'Check'
else
'In DB'
else if FirstTable.ColumnStatus = 2
'Revision'
else if FirstTable.ColumnStatus = 3
'Sent'
Edit 2
This is an example
I want Select All Rows From Employment Table
and I want to parse column Status to Column As "StatusName"
if Status = 1 It has two values
First value Check if QualificationID and SpecializationID Has Rows
in Table 'Vacancies' return 'Check'
and if no rows in Table 'Vacancies' return 'In DB'
if Status = 2 'Revision'
if Status = 3 'Sent'
You need to change your case and add more conditions:
SELECT ID, UserName,
CASE
WHEN [Status] = 1
AND EXISTS (SELECT 1
FROM Logs_TB
WHERE Logs_TB.UserName = Users_TB.UserName) THEN 'Check'
WHEN [Status] = 1 THEN 'In DB'
WHEN [Status] = 2 THEN 'Revision'
WHEN [Status] = 3 THEN 'Sent'
ELSE NULL
END AS StatusName
FROM Users_TB
CROSS JOIN Logs_TB
For performance reason is better to use EXISTS instead of comparing COUNT with 0.
Try this
DECLARE #Cnt INT
SELECT #Cnt = COUNT(*)
FROM Logs_TB
WHERE Logs_TB.UserName = Users_TB.UserName
SELECT
ID
,UserName
,CASE WHEN [Status] = 1
THEN
CASE WHEN #Cnt > 0
THEN 'Check'
ELSE 'In DB'
END
WHEN [Status] = 2 THEN 'Revision'
WHEN [Status] = 3 THEN 'Sent'
END AS StatusName
FROM Users_TB
CROSS JOIN Logs_TB

Resources