SQL Query for CASE Statement - sql-server

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

Related

Find all ids which occur once in a id column and have flag 1

I want the Ids which occur only once and then should have Flag = true
Sample data:
Id Flag Value
1 true frc
1 true yui
2 false tyty
3 true yul
3 false tuo
4 true poi
Result:
4
Give this a try:
SELECT a.id
FROM table a
left outer join table b
on a.id = b.id
where a.flag = 'true'
group by a.id
having count(*) = 1

select distinct with parent-child and return boolean for at least one child with a value?

I am currently searching for orders that have at least one orderline (product) with a certain boolean set:
- the product is a subscription product
- the product is a setup product
If one of the orderlines has this value set to 1, I want to return this in the query per DISTINCT order ID.
This does not seem to work for me:
SELECT DISTINCT [ORDER].[order_id]
,[ORDERLINE].[is_subscription] AS hasSubArticles
,[ORDERLINE].[is_setup] AS hasSetupArticles
FROM [ORDER]
LEFT JOIN [ORDERLINE]
ON [ORDER].[order_id] = [ORDERLINE].[f_order_id]
WHERE [G_ORDER].[status] = 1
ORDER BY [ORDER].[order_id]
,[ORDERLINE].[is_subscription] AS hasSubArticles
,[ORDERLINE].[is_setup] AS hasSetupArticles
When I check the returned records, I receive duplicate ORDER records:
order_id hasSubArticles hasSetupArticles
----------------------------------------
17804 NULL NULL
17804 1 0
I want to return only 1 record per order ID, thus this isn't working for me.
What am I doing wrong?
Distinct does not work for your requirement. MAX, Min functions are not allowed to use with bit type. You could use Group by and SUM like this
SELECT
[ORDER].[order_id]
,CASE WHEN SUM( CASE WHEN [ORDERLINE].[is_subscription] = 1 THEN 1 ELSE 0 END) > 0 THEN 1
ELSE 0
END AS hasSubArticles
,CASE WHEN SUM( CASE WHEN [ORDERLINE].[is_setup] = 1 THEN 1 ELSE 0 END) > 0
THEN 1
ELSE 0
END hasSetupArticles
FROM [ORDER]
LEFT JOIN [ORDERLINE]
ON [ORDER].[order_id] = [ORDERLINE].[f_order_id]
WHERE [G_ORDER].[status] = 1
GROUP BY [ORDER].[order_id]

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

Sql query to create teams

I need a query to assign teams to a series of users. Data looks like this:
UserId Category Team
1 A null
2 A null
3 B null
4 B null
5 A null
6 B null
8 A null
9 B null
11 B null
Teams should be created by sorting by userid and the first userid becomes the team number and the consecutive A's are part of that team as are the B's that follow. The first A after the Bs starts a new team. There will always be at least one A and one B. So after the update, that data should look like this:
UserId Category Team
1 A 1
2 A 1
3 B 1
4 B 1
5 A 5
6 B 5
8 A 8
9 B 8
11 B 8
EDIT:
Need to add that the user id's will not always increment by 1. I edited the example data to show what I mean. Also, the team ID doesn't strictly have to be the id of the first user, as long as they end up grouped properly. For example, users 1 - 4 could all be on team '1', users 5 and 6 on team '2' and users 8,9 and 11 on team '3'
First you could label each row with an increasing number. Then you can use a left join to find the previous user. If the previous user has category 'B', and the current one category 'A', that means the start of a new team. The team number is then the last UserId that started a new team before the current UserId.
Using SQL Server 2008 syntax:
; with numbered as
(
select row_number() over (order by UserId) rn
, *
from Table1
)
, changes as
(
select cur.UserId
, case
when prev.Category = 'B' and cur.Category = 'A' then cur.UserId
when prev.Category is null then cur.UserId
end as Team
from numbered cur
left join
numbered prev
on cur.rn = prev.rn + 1
)
update t1
set Team = team.Team
from Table1 t1
outer apply
(
select top 1 c.Team
from changes c
where c.UserId <= t1.UserId
and c.Team is not null
order by
c.UserId desc
) as team;
Example at SQL Fiddle.
You can do this with a recursive CTE:
with userCTE as
(
select UserId
, Category
, Team = UserId
from users where UserId = 1
union all
select users.UserId
, users.Category
, Team = case when users.Category = 'A' and userCTE.Category = 'B' then users.UserId else userCTE.Team end
from userCTE
inner join users on users.UserId = userCTE.UserId + 1
)
update users
set Team = userCTE.Team
from users
inner join userCTE on users.UserId = userCTE.UserId
option (maxrecursion 0)
SQL Fiddle demo.
Edit:
You can update the CTE to get this to go:
with userOrder as
(
select *
, userRank = row_number() over (order by userId)
from users
)
, userCTE as
(
select UserId
, Category
, Team = UserId
, userRank
from userOrder where UserId = (select min(UserId) from users)
union all
select users.UserId
, users.Category
, Team = case when users.Category = 'A' and userCTE.Category = 'B' then users.UserId else userCTE.Team end
, users.userRank
from userCTE
inner join userOrder users on users.userRank = userCTE.userRank + 1
)
update users
set Team = userCTE.Team
from users
inner join userCTE on users.UserId = userCTE.UserId
option (maxrecursion 0)
SQL Fiddle demo.
Edit:
For larger datasets you'll need to add the maxrecursion query hint; I've edited the previous queries to show this. From Books Online:
Specifies the maximum number of recursions allowed for this query.
number is a nonnegative integer between 0 and 32767. When 0 is
specified, no limit is applied.
In this case I've set it to 0, i.e. not limit on recursion.
Query Hints.
I actually ended up going with the following. It finished on all 3 million+ rows in a half an hour.
declare #userid int
declare #team int
declare #category char(1)
declare #lastcategory char(1)
set #userid = 1
set #lastcategory='B'
set #team=0
while #userid is not null
begin
select #category = category from users where userid = #userid
if #category = 'A' and #lastcategory = 'B'
begin
set #team = #userid
end
update users set team = #team where userid = #userid
set #lastcategory = #category
select #userid = MIN(userid) from users where userid > #userid
End

Case not working in Exists in Sql Server

I have a scenario where i have to check a variable for it's default value, and if it has i have to check EXISTS part conditionally with Table2 and if it does not have the default value, i have to check EXISTS part conditionally with Table3.
Below is a sample code:-
SELECT * FROM tbl1 WHERE EXISTS (SELECT CASE WHEN #boolVar = 0 THEN (SELECT 'X' FROM tbl2 WHERE tbl1.col1 = tbl2.col1) ELSE (SELECT 'X' FROM tbl3 where tbl1.col1 = tbl3.col1) END)
Demo query with constants for testing purpose: -
SELECT 1 WHERE EXISTS (SELECT CASE WHEN 1 = 0 THEN (SELECT 'X' WHERE 1=0)
ELSE (SELECT 'X' WHERE 1 = 2) END)
Note: - The above query always returning 1, even not a single condition is satisfying.
I know we can use OR operator for the same and any how we can achieve it, but i really want to know that in case both the tables have no rows satisfying their particular where clause, even it's returning all the rows from Table1.
I tried to explain the same with the demo query with constant values.
Please help.
When your query doesn't find any matching records, it will basically do:
SELECT 1 WHERE EXISTS (SELECT NULL)
As a row containing a null value is still a row, the EXISTS command returns true.
You can add a condition to filter out the null row:
SELECT * FROM tbl1 WHERE EXISTS (
SELECT 1 FROM (
SELECT
CASE WHEN #boolVar = 0 THEN (SELECT 'X' FROM tbl2 WHERE tbl1.col1 = tbl2.col1)
ELSE (SELECT 'X' FROM tbl3 where tbl1.col1 = tbl3.col1)
END AS Y
) Z
WHERE Y IS NOT NULL
)
Here's an alternative, just in case:
SELECT *
FROM Table1
WHERE EXISTS (
SELECT 1
FROM Table2
WHERE #var = #defValue
AND ... /* other conditions as necessary */
UNION ALL
SELECT 1
FROM Table3
WHERE #var <> #defValue
AND ... /* other conditions as necessary */
);

Resources