How do I use this condition inside CASE WHEN? - sql-server

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

Related

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

Check if record exists while inserting using User defined table type sql server

I am trying to bulk insert the records in sql server. I am using User Defined Table type to pass the collection of records from my .net application. Please take a look at the insert query below.
INSERT INTO MachineItems([Name],[Price],[Quantity],[ItemGroupID],[SubGroup] ,[IsDefault],
[IsRemovable],[MachineTypeID],[ItemType],[CreatedBy],[CreatedOn] )
SELECT mi.Name
,mi.Price
,mi.Quantity
,(SELECT ID from ItemGroups WHERE NAME=mi.ItemGroup) as ID
,mi.SubGroup,
CASE
WHEN mi.IsDefault ='Yes' THEN 1
WHEN mi.IsDefault ='No' THEN 0
WHEN mi.IsDefault IS NULL THEN 0
END ,
CASE
WHEN mi.IsRemovable ='Yes' THEN 1
WHEN mi.IsRemovable ='No' THEN 0
END ,
(SELECT ID from MachineTypes WHERE Name=mi.MachineType),
(SELECT ID from MachineItemTypes WHERE Name=mi.ItemType),
mi.CreatedBy
,mi.CreatedOn
FROM #MachineItems mi
What i want to do is put the check before inserting the records , Whether record with [MachineTypeID] and [Name] already exists in table or not. If it does not exists then insert Eles Update the record.
How can i do that with User Defined Table Type ?
You should use the MERGE command rather than a straight insert. What you are wanting to do is not really specific to User-Defined Table Types.
It would be better / more efficient if you joined the 3 subtables rather than having subqueries for columns which will execute per-row.
Example:
MERGE MachineItems AS Target
USING (SELECT mi.Name,
mi.Price,
mi.Quantity,
ig.ID, -- ItemGroupID
mi.SubGroup,
CASE
WHEN mi.IsDefault ='Yes' THEN 1
WHEN mi.IsDefault ='No' THEN 0
WHEN mi.IsDefault IS NULL THEN 0
END, -- IsDefault
CASE
WHEN mi.IsRemovable ='Yes' THEN 1
WHEN mi.IsRemovable ='No' THEN 0
END, -- IsRemovable
mt.ID, -- MachineTypeID
mit.ID, -- ItemType
mi.CreatedBy,
mi.CreatedOn
FROM #MachineItems mi
INNER JOIN ItemGroups ig
ON ig.[Name] = mi.ItemGroup
INNER JOIN MachineTypes mt
ON mt.[Name] = mi.MachineType
INNER JOIN MachineItemTypes mit
ON mit.[Name] = mi.ItemType) AS Source (
[Name],[Price],[Quantity],[ItemGroupID],[SubGroup],[IsDefault],
[IsRemovable],[MachineTypeID],[ItemType],[CreatedBy],[CreatedOn])
ON (
Target.[MachineTypeID] = Source.[MachineTypeID]
AND Target.[Name] = Source.[Name]
)
WHEN MATCHED THEN
UPDATE SET Price = Source.Price,
Quantity = Source.Quantity,
ItemGroupID = Source.ItemGroupID,
SubGroup = Source.SubGroup,
IsDefault = Source.IsDefault,
IsRemovable = Source.IsRemovable,
MachineTypeID = Source.MachineTypeID,
ItemType = Source.ItemType,
CreatedBy = Source.CreatedBy,
CreatedOn = Source.CreatedOn
WHEN NOT MATCHED BY TARGET THEN
INSERT ([Name],[Price],[Quantity],[ItemGroupID],[SubGroup] ,[IsDefault],
[IsRemovable],[MachineTypeID],[ItemType],[CreatedBy],[CreatedOn])
VALUES (Source.[Name], Source.[Price], Source.[Quantity], Source.[ItemGroupID],
Source.[SubGroup], Source.[IsDefault], Source.[IsRemovable],
Source.[MachineTypeID], Source.[ItemType], Source.[CreatedBy],
Source.[CreatedOn]);
You can Use Merge Here
Using Merge
You can Insert if Not Exists
You can Delete if Already Exists
You can Update if Already Exists
MERGE MachineItems
USING #MachineItems ON MachineItems.id = #MachineItems.id
and MachineItems.Name=#MachineItems.Name
WHEN NOT MATCHED THEN
INSERT INTO MachineItems([Name],[Price],[Quantity],[ItemGroupID],[SubGroup]
,[IsDefault],
[IsRemovable],[MachineTypeID],[ItemType],[CreatedBy],[CreatedOn] )
SELECT mi.Name
,mi.Price
,mi.Quantity
,(SELECT ID from ItemGroups WHERE NAME=mi.ItemGroup) as ID
,mi.SubGroup,
CASE
WHEN mi.IsDefault ='Yes' THEN 1
WHEN mi.IsDefault ='No' THEN 0
WHEN mi.IsDefault IS NULL THEN 0
END ,
CASE
WHEN mi.IsRemovable ='Yes' THEN 1
WHEN mi.IsRemovable ='No' THEN 0
END ,
(SELECT ID from MachineTypes WHERE Name=mi.MachineType),
(SELECT ID from MachineItemTypes WHERE Name=mi.ItemType),
mi.CreatedBy
,mi.CreatedOn
FROM #MachineItems mi

joining on count and rank the result t sql

Here's my Count_query:
Declare #yes_count decimal;
Declare #no_count decimal;
set #yes_count=(Select count(*) from Master_Data where Received_Data='Yes');
set #no_count=(Select count(*) from Master_Data where Received_Data='No');
select #yes_count As Yes_Count,#no_count as No_Count,(#yes_count/(#yes_count+#no_count)) As Submission_Count
I am having trouble making joins on these two queries
This is the rest of the query:
Select Distinct D.Member_Id,d.Name,d.Region_Name, D.Domain,e.Goal_Abbreviation,
e.Received_Data, case when Received_Data = 'Service Not Provided' then null
when Received_Data = 'No' then null else e.Improvement end as
Percent_Improvement , case when Received_Data = 'Service Not Provided' then null
when Received_Data = 'No' then null else e.Met_40_20 end as Met_40_20
FROM (
select distinct member_Domains.*,
(case when NoData.Member_Id is null then 'Participating' else ' ' end) as Participating
from
(
select distinct members.Member_Id, members.Name, Members.Region_Name,
case when Domains.Goal_Abbreviation = 'EED Reduction' then 'EED'
When Domains.Goal_Abbreviation = 'Pressure Ulcers' then 'PRU'
when Domains.Goal_Abbreviation = 'Readmissions' then 'READ' else Domains.Goal_Abbreviation end as Domain from
(select g.* from Program_Structure as ps inner join Goal as g on ps.Goal_Id = g.Goal_Id
and ps.Parent_Goal_ID = 0) as Domains
cross join
(select distinct hc.Member_ID, hc.Name,hc.Region_Name from zsheet as z
inner join Hospital_Customers$ as hc on z.CCN = hc.Mcare_Id) as Members
) as member_Domains
left outer join Z_Values_Hospitals as NoData on member_Domains.member_ID = NoData.Member_Id
and Member_Domains.Domain = noData.ReportName) D
Left Outer JOIN
(SELECT B.Member_ID, B.Goal_Abbreviation, B.minRate, C.maxRate, B.BLine, C.Curr_Quarter, B.S_Domain,
(CASE WHEN B.Member_ID IN
(SELECT member_id
FROM Null_Report
WHERE ReportName = B.S_Domain) THEN 'Service Not Provided' WHEN Curr_Quarter = 240 THEN 'Yes' ELSE 'No' END) AS Received_Data,
ROUND((CASE WHEN minRate = 0 AND maxRate = 0 THEN 0 WHEN minRate = 0 AND maxRate > 0 THEN 1 ELSE (((maxRate - minRate) / minRate) * 100) END), .2) AS Improvement,
(CASE WHEN ((CASE WHEN minRate = 0 AND maxRate = 0 THEN 0 WHEN minRate = 0 AND maxRate > 0 THEN 1 ELSE (maxRate - minRate) / minRate END)) <= - 0.4 OR
maxRate = 0 THEN 'Yes' WHEN ((CASE WHEN minRate = 0 AND maxRate = 0 THEN 0 WHEN minRate = 0 AND maxRate > 0 THEN 1 ELSE (maxRate - minRate) / minRate END))
<= - 0.2 OR maxRate = 0 THEN 'Yes' ELSE 'No' END) AS Met_40_20
FROM (SELECT tab.Member_ID, tab.Measure_Value AS minRate, tab.Goal_Abbreviation, A.BLine, tab.S_Domain
FROM Measure_Table_Description AS tab INNER JOIN
(SELECT DISTINCT
Member_ID AS new_memid, Goal_Abbreviation AS new_measure, MIN(Reporting_Period_ID) AS BLine, MAX(Reporting_Period_ID)
AS Curr_Quarter
FROM Measure_Table_Description
WHERE (Member_ID > 1) AND (Measure_Value IS NOT NULL) AND (Measure_ID LIKE '%O%')
GROUP BY Goal_Abbreviation, Member_ID) AS A ON tab.Member_ID = A.new_memid AND tab.Reporting_Period_ID = A.BLine AND
tab.Goal_Abbreviation = A.new_measure) AS B FULL OUTER JOIN
(SELECT tab.Member_ID, tab.Measure_Value AS maxRate, tab.Goal_Abbreviation, A_1.Curr_Quarter
FROM Measure_Table_Description AS tab INNER JOIN
(SELECT DISTINCT
Member_ID AS new_memid, Goal_Abbreviation AS new_measure,
MIN(Reporting_Period_ID) AS BLine, MAX(Reporting_Period_ID)
AS Curr_Quarter
FROM Measure_Table_Description AS Measure_Table_Description_1
WHERE (Member_ID >1) AND (Measure_Value IS NOT NULL) AND (Measure_ID LIKE '%O%')
GROUP BY Goal_Abbreviation, Member_ID) AS A_1 ON tab.Member_ID = A_1.new_memid
AND tab.Reporting_Period_ID = A_1.Curr_Quarter AND
tab.Goal_Abbreviation = A_1.new_measure) AS C ON B.Member_ID = C.Member_ID
WHERE (B.Goal_Abbreviation = C.Goal_Abbreviation) ) E ON D.Member_Id = E.Member_ID AND d.Domain = E.S_Domain
ORDER BY D.Domain,D.Member_ID
How do I get a count of the 'yes'/ (count(yes)+count(no)) for each member_ID as column1 and also display the rank of each member_ID against all the member_IDs in the result as column2. I have come up with a query that generates the count for the entire table, but how do I restrict it each Member_ID.
Thanks for your help.
I haven't taken the time to digest your provided query, but if abstracted to the concept of having an aggregate over a range of data repeated on each row, you should look at using windowing functions. There are other methods, such as using a CTE to do your aggregation and then JOINing back to your detailed data. That might work better for more complex calculations, but the window functions are arguably the more elegant option.
DECLARE #MasterData AS TABLE
(
MemberID varchar(50),
MemberAnswer int
);
INSERT INTO #MasterData (MemberID, MemberAnswer) VALUES ('Jim', 1);
INSERT INTO #MasterData (MemberID, MemberAnswer) VALUES ('Jim', 0);
INSERT INTO #MasterData (MemberID, MemberAnswer) VALUES ('Jim', 1);
INSERT INTO #MasterData (MemberID, MemberAnswer) VALUES ('Jim', 1);
INSERT INTO #MasterData (MemberID, MemberAnswer) VALUES ('Jane', 1);
INSERT INTO #MasterData (MemberID, MemberAnswer) VALUES ('Jane', 0);
INSERT INTO #MasterData (MemberID, MemberAnswer) VALUES ('Jane', 1);
-- Method 1, using windowing functions (preferred for performance and syntactical compactness)
SELECT
MemberID,
MemberAnswer,
CONVERT(numeric(19,4),SUM(MemberAnswer) OVER (PARTITION BY MemberID)) / CONVERT(numeric(19,4),COUNT(MemberAnswer) OVER (PARTITION BY MemberID)) AS PercentYes
FROM #MasterData;
-- Method 2, using a CTE
WITH MemberSummary AS
(
SELECT
MemberID,
SUM(MemberAnswer) AS MemberYes,
COUNT(MemberAnswer) AS MemberTotal
FROM #MasterData
GROUP BY MemberID
)
SELECT
md.MemberID,
md.MemberAnswer,
CONVERT(numeric(19,4),MemberYes) / CONVERT(numeric(19,4),MemberTotal) AS PercentYes
FROM #MasterData md
JOIN MemberSummary ms
ON md.MemberID = ms.MemberID;
First thought is: your query is much, much too complicated. I have spent about 10 minutes now trying to make sense of it and haven't gotten anywhere, so it's obviously going to pose a long-term maintenance challenge to those within your organization going forward as well. I would really recommend you try to find some way of simplifying it.
That said, here is a simplified, general example of how to query on a calculated value and rank the results:
CREATE TABLE member (member_id INT PRIMARY KEY);
CREATE TABLE master_data (
transaction_id INT PRIMARY KEY,
member_id INT FOREIGN KEY REFERENCES member(member_id),
received_data BIT
);
-- INSERT data here
; WITH member_data_counts AS (
SELECT
m.member_id,
(SELECT COUNT(*) FROM master_data d WHERE d.member_id = m.member_id AND d.received_data = 1) num_yes,
(SELECT COUNT(*) FROM master_data d WHERE d.member_id = m.member_id AND d.received_data = 0) num_no
FROM member m
), member_data_calc AS (
SELECT
*,
CASE
WHEN (num_yes + num_no) = 0 THEN NULL -- avoid division-by-zero error
ELSE num_yes / (num_yes + num_no)
END pct_yes
FROM member_data_counts
), member_data_rank AS (
SELECT *, RANK() OVER (ORDER BY pct_yes DESC) AS RankValue
FROM member_data_calc
)
SELECT *
FROM member_data_rank
ORDER BY RankValue ASC;

Subquery in CTE

i'm trying to get the status of student after the semester ends
and then update the status in it's table
can i use subquery inside the CTE ??
;with temp As
(
select CASE WHEN Status = 0 then 'Passed'
when status >0 and status < 2 then 'uncomplete'
else 'Failed' end Studentstatus
from
(
SELECT StudentID,
sum(CASE WHEN CourseStatus =1 then 1 else 0 end) Status
FROM StudentFinalResultsDetails
group by StudentID
)As t
)--the error in this line
the problem is
Incorrect syntax near ')'
You don't need a subquery for this, either use a CTE or subquery; you are mixing both of them, just do this:
with temp As
(
SELECT StudentID,
sum(CASE WHEN CourseStatus =1 then 1 else 0 end) Status
FROM StudentFinalResultsDetails
group by StudentID
) -- You have to select something after the brackets
select CASE WHEN Status = 0 then 'Passed'
when status >0 and status < 2 then 'uncomplete'
else 'Failed' end AS Studentstatus
from temp
Or: remove WITH CTE:
select CASE WHEN Status = 0 then 'Passed'
when status >0 and status < 2 then 'uncomplete'
else 'Failed' end Studentstatus
from
(
SELECT StudentID,
sum(CASE WHEN CourseStatus =1 then 1 else 0 end) Status
FROM StudentFinalResultsDetails
group by StudentID
)As t
Update
The problem in the query in your question, you have to move the part:
select CASE WHEN Status = 0 then 'Passed'
when status >0 and status < 2 then 'uncomplete'
else 'Failed' end AS Studentstatus`
to the outer of the brackets of the WITH temp ( .... ) then after it select whatever you want from it.
Because:
A CTE must be followed by a single SELECT, INSERT, UPDATE, or DELETE
statement that references some or all the CTE columns. A CTE can also
be specified in a CREATE VIEW statement as part of the defining SELECT
statement of the view.
In your query, you didn't put any statements after it. See reference

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

Resources