SQL CASE Logic Issue - sql

Could someone please assist me? Example: Problem I am having is when an account has AV.Query='PN4', AV.Response = 'Y', AV.Query='FL1' and AV.Response='Y', the result needs to be
PStatus IStatus
4 2
However, I am getting
PStatus IStatus
4 5
5 2
It picks "5" all the time on the opposite column.
SELECT distinct A.AcctNum,
CASE
WHEN O.Order = 'NEI2' THEN '1'
WHEN AV.Query IN ('PNE1','PNE2') AND AV.Response = 'Y' THEN '2'
WHEN AV.Query = 'PN20' AND AV.Response = 'Y' THEN '3'
WHEN AV.Query = 'PN4' AND AV.Response = 'Y' THEN '4'
ELSE '5'
END AS [PStatus],
CASE
WHEN O.Order IN ('DO2','FL25','VACHP') THEN '1'
WHEN AV.Query = 'FL1' AND AV.Response = 'Y' THEN '2'
WHEN AV.Query = 'REF' AND AV.Response = 'Y' THEN '3'
WHEN AV.Query IN ('FL2','FL6','NEU.G','HE.B') AND AV.Response = 'Y' THEN '4'
WHEN AV.Query = 'NOA' AND AV.Response = 'Y' THEN '6'
ELSE '5'
END AS [IStatus]
FROM AData AS AD
INNER JOIN AVisit AS AV
ON AD.Visit = AV.Visit
AND AV.QueryID IN ('PNE1','PNE2','PN20','PN4','FL1','REF','FL2','FL6','NEU.G','HE.B','NOA')
LEFT JOIN Order AS O
ON AD.Visit = O.Visit
AND O.Order IN ('NEI2','DO2','FL25','VACHP');

Your results appear to be correct for the query.
Consider first the row of the join that has
AV.Query='PN4', AV.Response = 'Y',
This matches the last WHEN condition in the CASE expression for [PStatus], but it does not match any of the WHEN conditions in the CASE expression for [IStatus]. Result:
4 5
Consider now the join row having
AV.Query='FL1' and AV.Response='Y'
This does not match any WHEN condition in the CASE expression for [PStatus], but it matches the second WHEN conditions in the CASE expression for [IStatus]. Result:
5 2
I could give you a variation on your query that produces the results you specified for the particular data you present, but I do not do so because there are many alternatives, and you haven't given us the information to determine which one correctly answers the question for other data.
UPDATE:
To combine multiple result rows into one, you require an aggregate query. One possible way to implement such a query to provide a single row having values 4, 2 for your given data would be
SELECT
AcctNum,
MIN(
CASE
WHEN O.Order = 'NEI2' THEN '1'
WHEN AV.Query IN ('PNE1','PNE2') AND AV.Response = 'Y' THEN '2'
WHEN AV.Query = 'PN20' AND AV.Response = 'Y' THEN '3'
WHEN AV.Query = 'PN4' AND AV.Response = 'Y' THEN '4'
ELSE NULL
END
) AS [Pstatus],
MIN(
CASE
WHEN O.Order IN ('DO2','FL25','VACHP') THEN '1'
WHEN AV.Query = 'FL1' AND AV.Response = 'Y' THEN '2'
WHEN AV.Query = 'REF' AND AV.Response = 'Y' THEN '3'
WHEN AV.Query IN ('FL2','FL6','NEU.G','HE.B') AND AV.Response = 'Y' THEN '4'
WHEN AV.Query = 'NOA' AND AV.Response = 'Y' THEN '6'
ELSE NULL
END
) AS [IStatus]
FROM
AData AS AD
INNER JOIN AVisit AS AV
ON AD.Visit = AV.Visit
AND AV.QueryID IN ('PNE1','PNE2','PN20','PN4','FL1','REF','FL2','FL6','NEU.G','HE.B','NOA')
LEFT JOIN Order AS O
ON AD.Visit = O.Visit
AND O.Order IN ('NEI2','DO2','FL25','VACHP');
GROUP BY AcctNum
This works because aggregate functions other than COUNT() ignore NULLs. It very likely will not give the desired answer for different data patterns, however -- especially patterns where there are more than two AVisits for the same account.

Results are correct.
Your values are:
First row - AV.Query='PN4', AV.Response = 'Y'
Second row - AV.Query='FL1', AV.Response='Y'
First CASE PStatus: Result is 4 as you expected.
Next Case, Istatus. Here is probably lying misunderstanding, Because SQL will process still the same values (First row). This CASE will check against values: AV.Query='PN4', AV.Response = 'Y' from first line. Not against your second values (AV.Query='FL1' and AV.Response='Y').
Values 'PN4' and 'FL1' can not be in same Column in a same line! One column can have only one value, not two. You are probably expecting that in this second case SQL will start fetching another (second) line of data. But it is not.
Second case result is correct Because in the CASE there is not condition for value PN4, so it is end up as ELSE = 5
OK Edit, do it like this, this brute force, but will work ;-)
SELECT A.AcctNum,
COALESCE(MAX( CASE
WHEN O.Order = 'NEI2' THEN '1'
WHEN AV.Query IN ('PNE1','PNE2') AND AV.Response = 'Y' THEN '2'
WHEN AV.Query = 'PN20' AND AV.Response = 'Y' THEN '3'
WHEN AV.Query = 'PN4' AND AV.Response = 'Y' THEN '4'
ELSE NULL
END),5) AS [PStatus],
COALESCE(MAX(CASE
WHEN O.Order IN ('DO2','FL25','VACHP') THEN '1'
WHEN AV.Query = 'FL1' AND AV.Response = 'Y' THEN '2'
WHEN AV.Query = 'REF' AND AV.Response = 'Y' THEN '3'
WHEN AV.Query IN ('FL2','FL6','NEU.G','HE.B') AND AV.Response = 'Y' THEN '4'
WHEN AV.Query = 'NOA' AND AV.Response = 'Y' THEN '6'
ELSE NULL
END),5) AS [IStatus]

Related

Nested CASE statements in SQL

I am running the below SQL and I need to add a case statement for the svcState column.
I have a value defined for each number in that column which I need to have in my query. For instance 7 is OK, 4 is down etc. I tried adding this in the CASE statement as below and it seems, the syntax is incorrect. Any help will be greatly appreciated.
SELECT * FROM
(
SELECT
A.NodeName AS NodeName,
MAX(CASE WHEN Poller_Name='svcServiceName' THEN CAST(Status AS varchar) ELSE ''END) svcServiceName,
MAX(CASE (CASE WHEN Poller_Name='svcState' AND Status ='7' THEN 'OK'
WHEN Poller_Name='svcstate' AND Status ='4' THEN 'OUT OF SERVICE' END)
THEN CAST(Status AS bigint) ELSE '' END) svcState
FROM
(
SELECT
Nodes.Caption AS NodeName, CustomNodePollers_CustomPollers.UniqueName AS Poller_Name, CustomNodePollerStatus_CustomPollerStatus.Status AS Status, CustomNodePollerStatus_CustomPollerStatus.rowid as row, CustomNodePollerStatus_CustomPollerStatus.RawStatus as RawStatus
FROM
((Nodes INNER JOIN CustomPollerAssignment CustomNodePollerAssignment_CustomPollerAssignment ON (Nodes.NodeID = CustomNodePollerAssignment_CustomPollerAssignment.NodeID)) INNER JOIN CustomPollers CustomNodePollers_CustomPollers ON (CustomNodePollerAssignment_CustomPollerAssignment.CustomPollerID = CustomNodePollers_CustomPollers.CustomPollerID)) INNER JOIN CustomPollerStatus CustomNodePollerStatus_CustomPollerStatus ON (CustomNodePollerAssignment_CustomPollerAssignment.CustomPollerAssignmentID = CustomNodePollerStatus_CustomPollerStatus.CustomPollerAssignmentID)
WHERE
(
(CustomNodePollers_CustomPollers.UniqueName = 'svcServiceName') OR
(CustomNodePollers_CustomPollers.UniqueName = 'svcState')
)
AND
(
(CustomNodePollerAssignment_CustomPollerAssignment.InterfaceID = 0)
)
and Nodes.Caption = '101'
)A
GROUP BY NodeName, row
--ORDER BY svcServiceName
) B
Desired Output
MAX(CASE WHEN Poller_Name = 'svcState' THEN (CASE WHEN status = '7' THEN 'OK' ELSE 'DOWN' END) END)
Or...
MAX(CASE WHEN Poller_Name = 'svcState' AND status = '7' THEN 'OK'
WHEN Poller_Name = 'svcState' AND status = '4' THEN 'DOWN' END)
Or...
MAX(CASE WHEN Poller_Name != 'svcState' THEN NULL -- Assumes the poller_name is never NULL
WHEN status = '7' THEN 'OK'
WHEN status = '4' THEN 'DOWN'
END)
Where there is no ELSE specified, it is implicitly ELSE NULL, and NULL values are skipped by the MAX().

SQL Case - grouping values returned by ELSE

How can I receive only one row for category "Other" with a total of 111?
Wrap the CASE query up in a derived table, GROUP BY its result.
select "Channel", count(*) AS "Orders per Channel"
from
(
SELECT CASE hhhogcl
WHEN 'P' THEN 'One Step'
WHEN 'O' THEN 'Customer Service'
WHEN 'R' THEN 'Remote FTP'
WHEN 'N' THEN 'PowerNet'
WHEN 'S' THEN 'PowerSell'
WHEN 'M' THEN 'PowerMobile'
ELSE 'Other'
END AS "Channel",
FROM s2151bdw.pwrdta.ffdcstbp
JOIN s2151bdw.pwrdta.hhhordhl0
ON hhhcusn = ffdcusn
WHERE hhhcmpn = 1
AND hhhdivn = 1
AND hhhdptn = 1
AND hhhdtes > 0 --Ship Date AND HHHDTES BETWEEN 20180611 AND 20180611
) dt
GROUP BY "Channel"
ANSI SQL compliant!
You should GROUP BY CASE expression instead of HHHOGCL:
SELECT CASE hhhogcl
WHEN 'P' THEN 'One Step'
WHEN 'O' THEN 'Customer Service'
WHEN 'R' THEN 'Remote FTP'
WHEN 'N' THEN 'PowerNet'
WHEN 'S' THEN 'PowerSell'
WHEN 'M' THEN 'PowerMobile'
ELSE 'Other'
END AS "Channel",
Count(*) AS "Orders per Channel"
FROM s2151bdw.pwrdta.ffdcstbp
JOIN s2151bdw.pwrdta.hhhordhl0
ON hhhcusn = ffdcusn
WHERE hhhcmpn = 1
AND hhhdivn = 1
AND hhhdptn = 1
AND hhhdtes > 0 --Ship Date AND HHHDTES BETWEEN 20180611 AND 20180611
GROUP BY
CASE hhhogcl
WHEN 'P' THEN 'One Step'
WHEN 'O' THEN 'Customer Service'
WHEN 'R' THEN 'Remote FTP'
WHEN 'N' THEN 'PowerNet'
WHEN 'S' THEN 'PowerSell'
WHEN 'M' THEN 'PowerMobile'
ELSE 'Other'
END

How to handle with NULL values

I have the following code:
`SELECT nt.pl,
o.cat,
o.coun,
COUNT (DISTINCT nt.im) Sub,
SUM (nt.DOWN + nt.UP) Vol,
COUNT (*) AS counter,
CASE
WHEN nt.tele = '5' THEN 'Vo'
WHEN nt.tele = ('N/A') AND nt.rat = ('G') THEN 'G'
ELSE 'Unknown'
END
AS Service
FROM tmp nt, description o
WHERE nt.pl = o.pl AND nt.time LIKE '201605%'
GROUP BY nt.pl,
o.cat,
o.coun,
nt.tele,
nt.rat`
The problem is that the column rat contains NULL values and in the result I receive more rows than expected. How I could handle with these NULL values.
Thanks
I suspect that rather than having the nt.tele and nt.rat columns in the group by list, you want the case expression instead, e.g.:
SELECT nt.pl,
o.cat,
o.coun,
COUNT (DISTINCT nt.im) Sub,
SUM (nt.DOWN + nt.UP) Vol,
COUNT (*) AS counter,
CASE
WHEN nt.tele = '5' THEN 'Vo'
WHEN nt.tele = ('N/A') AND nt.rat = ('G') THEN 'G'
ELSE 'Unknown'
END
AS Service
FROM tmp nt, description o
WHERE nt.pl = o.pl AND nt.time LIKE '201605%'
GROUP BY nt.pl,
o.cat,
o.coun,
CASE
WHEN nt.tele = '5' THEN 'Vo'
WHEN nt.tele = ('N/A') AND nt.rat = ('G') THEN 'G'
ELSE 'Unknown'
END;
You are trying to filter the null value?
WHERE nt.pl = o.pl AND nt.time LIKE '201605%' AND nt.rat is not null
??

Can I add multiple summary rows in TSQL?

Goal: I am trying to add a summary row per school and I have this set up in Fiddle.
Needs:
List item I would like the enrollment totals for each year for Smith Elementary, Jones Elementary, etc.
List item I would also like to have summary rows for all levels (ES,MS,HS).
List item I would also like to have a grand total row for all levels.
Fiddle:
Is this possible in TSQL? I'm running SQL Server 2008 R2.
SELECT
schoolid,
sitename,
level,
area,
grade,
20122013ActualEnrollment ,
20132014ActualEnrollment,
20152016ActualEnrollment
FROM supportContacts
ORDER BY
CASE
WHEN Level= 'ES' THEN '1'
WHEN Level= 'MS' THEN '2'
WHEN Level= 'HS' THEN '3'
ELSE '4'
END
, SiteName
, CASE
WHEN Grade = 'K' THEN '1'
WHEN Grade = '1' THEN '2'
WHEN Grade = '2' THEN '3'
WHEN Grade = '3' THEN '4'
WHEN Grade = '4' THEN '5'
WHEN Grade = '5' THEN '6'
ELSE '7'
END
Output:
Thank you for your help!
Please realize this is pretty much a shot in the dark. I don't have the structure or sample data when writing this.
SELECT
SY12.[SchoolID]
, MAX(SY12.[SiteName])
, MAX(SY12.[Level])
, MAX(S.[AreaName])
, SY12.[Grade]
, SY12.[TotalEnrollment] AS '2012-2013 Actual Enrollment'
, SY13.[TotalEnrollment] AS '2013-2014 Actual Enrollment'
, P.[2016] AS '2015-2016 Projected Enrollment'
FROM
[2012Cycle1_Data] AS SY12
LEFT OUTER JOIN
[2013Cycle1_Data] AS SY13 ON SY12.SchoolID = SY13.[SchoolID]
AND SY12.Grade = SY13.Grade
LEFT OUTER JOIN
[Projections] AS P ON SY12.SchoolID = P.[SchoolID]
AND SY12.Grade = P.Grade
LEFT OUTER JOIN
v_Sites AS S ON SY12.SchoolID = S.SchoolID
GROUP BY SY12.[SchoolID], SY12.[Grade]
ORDER BY
CASE
WHEN SY12.Level= 'ES' THEN '1'
WHEN SY12.Level= 'MS' THEN '2'
WHEN SY12.Level= 'HS' THEN '3'
ELSE '4'
END
, SiteName
, CASE
WHEN SY12.Grade = 'K' THEN '1'
WHEN SY12.Grade = '1' THEN '2'
WHEN SY12.Grade = '2' THEN '3'
WHEN SY12.Grade = '3' THEN '4'
WHEN SY12.Grade = '4' THEN '5'
WHEN SY12.Grade = '5' THEN '6'
ELSE '7'
END
Looks like I have typos in the query. :(
SELECT
schoolid,
MAX(sitename),
MAX(level),
MAX(area),
grade,
SUM(20122013ActualEnrollment),
SUM(20132014ActualEnrollment),
SUM(20152016ActualEnrollment)
FROM supportContacts
GROUP BY schoolid, grade WITH ROLLUP
That worked in your fiddle. I know it is not ordered by but maybe you can run with it?

Merging data SQL Query

I have a query request where I have to show one customer activity for each web-site but it has to be only one row each, instead of one customer showing multiple times for each activity.
Following is the query I tried but brings lot more rows. please help me as how I can avoid duplicates and show only one customer by each row for each activity.
SELECT i.customer_id, i.SEGMENT AS Pistachio_segment,
(CASE when S.SUBSCRIPTION_TYPE = '5' then 'Y' else 'N' end ) PB_SUBS
(CASE WHEN S.SUBSCRIPTION_TYPE ='12' THEN 'Y' ELSE 'N' END) Daily_test,
(CASE when S.SUBSCRIPTION_TYPE ='8' then 'Y' else 'N' end) COOK_4_2
FROM IDEN_WITH_MAIL_ID i JOIN CUSTOMER_SUBSCRIPTION_FCT S
ON I.IDENTITY_ID = S.IDENTITY_ID and I.CUSTOMER_ID = S.CUSTOMER_ID
WHERE s.site_code ='PB' and s.subscription_end_date is null
Sounds like you need to group by customer_id and perform aggregations for the other columns you are selecting. For example:
sum(case when s.subscription_type = '5' then 1 else 0 end) as pb_subs_count
You could try one of two things:
Use a GROUP BY statement to combine all records with the same id, e.g.,
...
WHERE s.site_code ='PB' and s.subscription_end_date is null
GROUP BY i.customer_id
Use the DISTINCT command in your SELECT, e.g.,
SELECT DISTINCT i.customer_id, i.SEGMENT, ...
you could use a aggregation (SUM) on customer_id, but what do you expect to happen on the other fields? for example, if you have SUBSCRIPTION_TYPE 5 and 13 for the same customer (2 rows), which value do you want?
Perhaps you are looking for something like this:
SELECT i.customer_id, i.SEGMENT AS Pistachio_segment,
MAX(CASE when S.SUBSCRIPTION_TYPE = '5' then 'Y' else 'N' end ) PB_SUBS
MAX(CASE WHEN S.SUBSCRIPTION_TYPE ='12' THEN 'Y' ELSE 'N' END) Daily_test,
MAX(CASE when S.SUBSCRIPTION_TYPE ='8' then 'Y' else 'N' end) COOK_4_2
FROM IDEN_WITH_MAIL_ID i JOIN CUSTOMER_SUBSCRIPTION_FCT S
ON I.IDENTITY_ID = S.IDENTITY_ID and I.CUSTOMER_ID = S.CUSTOMER_ID
WHERE s.site_code ='PB' and s.subscription_end_date is null
GROUP BY i.customer_id, i.SEGMENT
I can't be sure, though, without knowing more about the tables involved.