SQL Server PIVOT Function To Switch Rows, Columns - sql-server

I'm trying to switch rows and columns with PIVOT (or another method). The documentation is pretty confusing to me. Thanks
DECLARE #CallCenterID Int;
DECLARE #BeginDateofReview SmallDateTime;
DECLARE #EndDateofReview SmallDateTime;
SELECT
COUNT(case when Score_Greeting = 'Yes' then Score_Greeting END) AS Score_Greeting_Passed,
SUM(CASE WHEN Score_Greeting IS NOT NULL THEN 1 ELSE 0 END) AS Score_Greeting_Reviewed,
ROUND(CONVERT(decimal(4,1), (COUNT(CASE WHEN Score_Greeting = 'Yes' THEN Score_Greeting END) * 100.0) / NULLIF(SUM(CASE WHEN Score_Greeting IS NOT NULL THEN 1 ELSE 0 END),0),0),0) AS Score_Greeting_PctngPassed,
COUNT(CASE WHEN Score_Authentication = 'Yes' THEN Score_Authentication END) AS Score_Authentication_Passed,
SUM(CASE WHEN Score_Authentication IS NOT NULL THEN 1 ELSE 0 END) AS Score_Authentication_Reviewed,
ROUND(CONVERT(decimal(4,1), (COUNT(CASE WHEN Score_Authentication = 'Yes' THEN Score_Authentication END) * 100.0) / NULLIF(SUM(CASE WHEN Score_Authentication IS NOT NULL THEN 1 ELSE 0 END), 0), 0), 0) AS Score_Authentication_PctngPassed,
FROM
Calls
WHERE
CallCenterID = #CallCenterID AND
(DateofReview >= #BeginDateofReview AND DateofReview <= #EndDateofReview)
Desired results:
Score_Greeting_Passed 5
Score_Greeting_Reviewed 9
Score_Greeting_PctngPassed 56
Score_Authentication_Passed 6
Score_Authentication_Reviewed 9
Score_Authentication_PctngPassed 67

You can use the UNPIVOT operator to transpose the rows and columns. If we assume your query above is stored in #YourData, it's going to be something like:
SELECT
UnpivotedData.ScoreType
, UnpivotedData.ScoreValue
FROM
#YourData
UNPIVOT (ScoreValue FOR ScoreType IN ( [Score_Greeting_Passed], [Score_Greeting_Reviewed], [Score_Greeting_PctngPassed],
[Score_Authentication_Passed], [Score_Authentication_Reviewed], [Score_Authentication_PctngPassed] )) AS UnpivotedData

Related

need help for select function in sql

In a table I have 914 rows in that I have a Column which contains "yes or no" values(Yes=193 No = 721 total 914).
In this I want to create a function to use in select statement How many Yes and No
I wrote a query
create function TSS(
#string as nvarchar(20)
)
returns int
begin
declare #result int
if (#string='NO')
select #result=sum(case Re_engaged when 'NO' then 1 else null end) from TVS_PRE
else if (#string='YES')
select #result=sum(case Re_engaged when 'YES' then 1 else null end) from TVS_PRE
return #result
end
select [dbo].[TSS]('Yes') as columns_with_Yes,[dbo].[TSS]('No') as columns_with_No from TVS_PRE
And I got the result is
Columns_with_Yes
Columns_with_No
1
193
2
193
3
193
upto...
...
914
193
but I required this
Columns_with_Yes
Columns_with_No
1
193
You should combine this into one query
SELECT
sum(case Re_engaged when 'NO' then 1 end) Columns_with_No,
sum(case Re_engaged when 'YES' then 1 end) Columns_with_Yes
FROM TVS_PRE;
If you really want this as a function, you can turn it into an inline Table valued Function
CREATE FUNCTION TSS()
RETURNS TABLE
AS RETURN (
SELECT
sum(case Re_engaged when 'NO' then 1 end) Columns_with_No,
sum(case Re_engaged when 'YES' then 1 end) Columns_with_Yes
FROM TVS_PRE
);
GO
I don't understand your need... but if you want only one row... then dont use "from":
select [dbo].[TSS]('Yes') as columns_with_Yes,[dbo].[TSS]('No') as columns_with_No
Use this syntax
SELECT DISTINCT COUNT(CASE WHEN Re_engaged='No' then 1 else NULL end) OVER () AS No_col,
COUNT(CASE WHEN Re_engaged='Yes' then 1 else NULL end) OVER () AS Yes_col
FROM TVS_PRE

Convert nvarchar to Int using Case When

Currently, i'm trying to convert '20190208-10h9m/1/1' to data type int. This string is identified under column String_Value. In addition, I'm pivoting using Case when syntax.
I've tried:
CASE WHEN PTXMEDE.PAT_ID = 'ID_TABLET' TEHN PTXMEDE.STRING_VALUE ELSE 0 END), CAST(PTXMEDE.STRING_VALUE As nvarchar) As ID_TABLET
I get a converting error.
Full syntax below:
Select
PTXMEDE.ME,
(CASE WHEN PTXMEDE.PAT_ID = 'ID_TABLET' THEN PTXMEDE.STRING_VALUE ELSE 0 END),CAST(PTXMEDE.STRING_VALUE As nvarchar) As ID_TABLET,
SUM(CASE WHEN PTXMEDE.PAT_ID = 'Q1_MD' THEN PTXMEDE.NUM_VALUE ELSE 0 END) As Q1_MD,
SUM(CASE WHEN PTXMEDE.PAT_ID = 'Q1_FPROB' THEN PTXMEDE.NUM_VALUE ELSE 0 END) As Q1_FPROB,
SUM(CASE WHEN PTXMEDE.PAT_ID = 'Q1_RESULT' THEN PTXMEDE.NUM_VALUE ELSE 0 END) As Q1_RESULT,
SUM(CASE WHEN PTXMEDE.PAT_ID = 'WEIGHT' THEN PTXMEDE.NUM_VALUE ELSE 0 END) As WEIGHT,
SUM(CASE WHEN PTXMEDE.PAT_ID = 'HARDNESS' THEN PTXMEDE.NUM_VALUE ELSE 0 END) As HARDNESS,
MAX(CASE WHEN PTXMEDE.PAT_ID = 'WEIGHT.T2+' THEN PTXMEDE.NUM_VALUE ELSE 0 END) As WEIGHTT2ULIMIT,
MAX(CASE WHEN PTXMEDE.PAT_ID = 'WEIGHT.T2-' THEN PTXMEDE.NUM_VALUE ELSE 0 END) As WEIGHTT2LLIMIT,
MAX(CASE WHEN PTXMEDE.PAT_ID = 'HARDNESS.T2-' THEN PTXMEDE.NUM_VALUE ELSE 0 END) As HARDNESST2LLIMIT,
MAX(CASE WHEN PTXMEDE.PAT_ID = 'CQA1Quality' THEN PTXMEDE.NUM_VALUE ELSE 0 END) As CQA1Quality,
MAX(CASE WHEN PTXMEDE.PAT_ID = 'CQA2Quality' THEN PTXMEDE.NUM_VALUE ELSE 0 END) As CQA2Quality,
MAX(CASE WHEN PTXMEDE.PAT_ID = 'CQA3Quality' THEN PTXMEDE.NUM_VALUE ELSE 0 END) As CQA2Quality,
PTXMEDE.DATE_LOCAL,
PTXMEDE.SEQUENCE
FROM
PTXMEDE
JOIN PTXMIIF ON
PTXMIIF.ME = PTXMEDE.ME
WHERE
PTXMEDE.ME IN (
SELECT ME FROM PTXME
WHERE CX_STRING_4 = '20190210-6h31m'
AND MT = 'CDC_CU'
)
GROUP By PTXMEDE.ME, PTXMEDE.DATE_LOCAL,PTXMEDE.NUM_VALUE,PTXMEDE.SEQUENCE,PTXMEDE.STRING_VALUE, PTXMEDE.PAT_ID
My Expected result is to be able to list the value under STRING_VALUE Column
All branches of a CASE expression must have the same type in SQL. An "exception" to this would be where they don't have the same type, but the database does some implicit converting to right things (e.g. such as in MySQL). Here is a corrected version of your CASE expression:
CASE WHEN PTXMEDE.PAT_ID = 'ID_TABLET' THEN PTXMEDE.STRING_VALUE ELSE '0' END
This would make the CASE expression output all text. If PTXMEDE.STRING_VALUE could be converted to an integer, then in theory you could also use this:
CASE WHEN PTXMEDE.PAT_ID = 'ID_TABLET' THEN CAST(PTXMEDE.STRING_VALUE AS INT) ELSE 0 END
This would have the CASE expression return an integer value.

How to do conditional select using SQL Server 2005

I have following query that I want to improve so it displays two additional columns as Variance and Percentage_Variance.
declare #w0s datetime
declare #w0e datetime
declare #w1s datetime
declare #w1e datetime
set #w0s = dateadd(hh, datediff(hh, 0, getdate()), 0)
set #w0e = getdate()
set #w1s = dateadd(dd, datediff(dd, 0, getdate()) / 7 * 7 - 7, 0)
set #w1e = dateadd(dd, datediff(dd, 0, getdate()) / 7 * 7, 0)
select
state,
sum(case
when create_time >= #w0s and create_time < #w0e
then 1 else 0
end) as Call_Volume_This_hr,
sum(case
when create_time >= #w1s and create_time < #w1e
then 1 else 0
end) / 7.0 as Avg_Call_Volume_Past_Week1
--,(case when ((sum(case when create_time>=#w0s and create_time<#w0e then 1 else 0 end)) - (sum(case when create_time>=#w1s and create_time<#w1e then 1 else 0 end)/7.0) > 0)then 1 else 0 end) as Variance
--,(case when (((case when ((sum(case when create_time>=#w0s and create_time<#w0e then 1 else 0 end)) - (sum(case when create_time>=#w1s and create_time<#w1e then 1 else 0 end)/7.0) > 0)then 1 else 0 end)/(sum(case when create_time>=#w1s and create_time<#w1e then 1 else 0 end)/7.0)*100.0) > 0) then 1 else 0 end) as Percentage_Variance
from
ctirpts.dbo.cti_reporting
where
create_time >= #w1s
and datepart(hh, create_time) = datepart(hour, getdate())
and state is not null
group by
state
;
The condition is that
if (Call_Volume_This_hr > Avg_Call_Volume_Past_Week1)
then
Variance = Call_Volume_This_hr - Avg_Call_Volume_Past_Week1
and
Percentage_Variance = (Variance/Avg_Call_Volume_Past_Week1)*100
else
Variance = 0 and Percentage_Variance = 0
The two commented lines shows my feeble attempt at getting this done but it prints 1 under columns "Variance" and "Percentage_Variance" when "if (Call_Volume_This_hr > Avg_Call_Volume_Past_Week1)" is true. Instead I want the actual computed values as per:
Variance = Call_Volume_This_hr - Avg_Call_Volume_Past_Week1
Percentage_Variance = (Variance/Avg_Call_Volume_Past_Week1)*100
I would appreciate any help or pointers.
You could put your initial select into a common table expression, then those calculated SUM columns become much more readily available for conditional computation. You can use an APPLY operator to perform the CASE statement, returning Variance of zero or more (never negatives). Then you can perform the calculation to get the percentage variance.
-- this CTE performs the initial aggregation and makes the recordset available
-- to be used like a table:
;with PreAggregate
as (
select state
,sum(case when create_time>=#w0s and create_time<#w0e then 1 else 0 end) as Call_Volume_This_hr
,sum(case when create_time>=#w1s and create_time<#w1e then 1 else 0 end)/7.0 as Avg_Call_Volume_Past_Week1
from ctirpts.dbo.cti_reporting
where create_time>=#w1s
and datepart(hh,create_time)=datepart(hour, getdate())
and state is not null
group by state
)
-- The APPLY operator creates an inline-table-value function without the
-- "black box" query optimizer problems of using an actual UDF
-- The "CROSS APPLY" calculates a 0 or more value for Variance.
-- The Variance value can then be used to compute Percentage_Variance.
select PreAggregate.state
, PreAggregate.Call_Volume_This_hr
, PreAggregate.Avg_Call_Volume_Past_Week1
, InlineFunction.Variance
, (InlineFunction.Variance/PreAggregate.Avg_Call_Volume_Past_Week1)*100 as 'Percentage_Variance'
from PreAggregate
cross apply (
select case
when Call_Volume_This_hr < Avg_Call_Volume_Past_Week1 then 0
else Call_Volume_This_hr -Avg_Call_Volume_Past_Week1
end 'Variance'
) InlineFunction;
I think your two commented lines should be as follows:
( ( SUM(CASE WHEN create_time >= #w0s
AND create_time < #w0e THEN 1
ELSE 0
END) ) - ( SUM(CASE WHEN create_time >= #w1s
AND create_time < #w1e THEN 1
ELSE 0
END) / 7.0 ) ) AS Variance,
( ( CASE WHEN ( ( SUM(CASE WHEN create_time >= #w0s
AND create_time < #w0e THEN 1
ELSE 0
END) ) - ( SUM(CASE WHEN create_time >= #w1s
AND create_time < #w1e THEN 1
ELSE 0
END) / 7.0 ) > 0 ) THEN 1
ELSE 0
END ) / ( SUM(CASE WHEN create_time >= #w1s
AND create_time < #w1e THEN 1
ELSE 0
END) / 7.0 ) * 100.0 ) AS Percentage_Variance
However without a fiddle or some structure and data I was unable to test it beyond correct syntax. Essentially the outermost CASE statements where the problem. They needed to be removed.

How To Get Non-Null,Non-0 for Average with SqlServer Select

**Note: I need to go a little further and add NULLIF(0 or 5). I wrote a short post about my answer here:
http://peterkellner.net/2013/10/13/creating-a-compound-nullif-in-avg-function-with-sqlserver/
but am not happy with my solution)
I've got a table with results where attendees type in estimated attendance to a course. If they type 0 or leave it empty, I want ignore that and get the average of values typed in. I can't figure out how to add that constraint to my AVG function without having a where clause for the entire SQL. Is that possible? My code looks like this: (EstimatedNumberAttendees is what I'm going after).
SELECT dbo.SessionEvals.SessionId,
AVG(Cast (dbo.SessionEvals.CourseAsWhole as Float)) AS CourseAsWholeAvg,
COUNT(*),
COUNT(case
when dbo.SessionEvals.InstructorPromptness = 'On Time' then 1
else null
end) AS SpeakerOnTime,
COUNT(case
when dbo.SessionEvals.InstructorPromptness = 'Late' then 1
else null
end) AS SpeakerLate,
COUNT(case
when dbo.SessionEvals.InstructorPromptness = 'NoShow' then 1
else null
end) AS SpeakerNoShow,
COUNT(case
when dbo.SessionEvals.PercentFull = '10% to 90%' then 1
else null
end) AS PercentFull10to90,
COUNT(case
when dbo.SessionEvals.PercentFull = '> 90%' then 1
else null
end) AS PercentFullGreaterThan90,
COUNT(case
when dbo.SessionEvals.PercentFull = ' < 10% Full ' then 1
else null
end) AS PercentFullLessThan10,
AVG(Cast (dbo.SessionEvals.EstimatedNumberAttendees as Float)) AS
EstimatedAttending
FROM dbo.Sessions
INNER JOIN dbo.SessionEvals ON (dbo.Sessions.Id =
dbo.SessionEvals.SessionId)
WHERE dbo.Sessions.CodeCampYearId = 8
GROUP BY dbo.SessionEvals.SessionId
AVG omits NULLs. Therefore make it treat 0s as NULLs. Use NULLIF for that:
...
AVG(NULLIF(Cast (dbo.SessionEvals.CourseAsWhole as Float), 0)) AS CourseAsWholeAvg,
...
AVG(NULLIF(Cast (dbo.SessionEvals.EstimatedNumberAttendees as Float), 0)) AS EstimatedAttending
...
You can try to use an inner query to get the same sessions but exclude zero and null:
SELECT dbo.SessionEvals.SessionId,
(
SELECT AVG(SE1.CourseAsWhole)
FROM dbo.SessionEvals SE1
WHERE SE1.SessionId = dbo.SessionEvals.SessionId
AND ISNULL(SE1.CourseAsWhole, 0) <> 0
) AS CourseAsWholeAvg,
COUNT(*),
COUNT(case
when dbo.SessionEvals.InstructorPromptness = 'On Time' then 1
else null
end) AS SpeakerOnTime,
COUNT(case
when dbo.SessionEvals.InstructorPromptness = 'Late' then 1
else null
end) AS SpeakerLate,
COUNT(case
when dbo.SessionEvals.InstructorPromptness = 'NoShow' then 1
else null
end) AS SpeakerNoShow,
COUNT(case
when dbo.SessionEvals.PercentFull = '10% to 90%' then 1
else null
end) AS PercentFull10to90,
COUNT(case
when dbo.SessionEvals.PercentFull = '> 90%' then 1
else null
end) AS PercentFullGreaterThan90,
COUNT(case
when dbo.SessionEvals.PercentFull = ' < 10% Full ' then 1
else null
end) AS PercentFullLessThan10,
AVG(Cast (dbo.SessionEvals.EstimatedNumberAttendees as Float)) AS
EstimatedAttending
FROM dbo.Sessions
INNER JOIN dbo.SessionEvals ON (dbo.Sessions.Id =
dbo.SessionEvals.SessionId)
WHERE dbo.Sessions.CodeCampYearId = 8
GROUP BY dbo.SessionEvals.SessionId
SQL AVG function will by default ignore null values so you need to only exclude the 0s. Your AVG code can be changed to below:
AVG(nullif( Cast(dbo.SessionEvals.CourseAsWhole as Float), 0) AS CourseAsWholeAvg

Set declaration and use in where clause in SQL Server

I have a SQL statement that has multiple case statements like the below:
SUM(CASE [Type]
WHEN 418
THEN CASE WHEN PMTS.DateCreated BETWEEN #sd AND #ed
AND( PMTS.Amount >0 OR PMTS.Mileage >0)
AND PMTS.PaymentEventID = 0 THEN Mileage END
ELSE 0 END) AS DriverMileage
But I need the result of the sum to set a variable and use that in the where in the WHERE clause.
Example below
DECLARE #contribution decimal
SElECT PMTS.VolunteerId ,
SET #contribution = SUM(CASE [Type]
WHEN 1003
THEN CASE WHEN PMTS.DateCreated BETWEEN #sd AND #ed
AND( PMTS.Amount >0 OR PMTS.Mileage >0)
AND PMTS.PaymentEventID = 0
THEN Amount END
ELSE 0 END) AS GPContributions
FROM PMTS WHERE #contribution >0
Many thanks
I don't think that you need a variable here, also please confirm the "case when" syntax used. Here is a sample query:
select * from
(SElECT PMTS.VolunteerId ,SUM(CASE [Type]
WHEN 1003
THEN CASE WHEN PMTS.DateCreated BETWEEN #sd AND #ed
AND( PMTS.Amount >0 OR PMTS.Mileage >0)
AND PMTS.PaymentEventID = 0
THEN Amount END
ELSE 0 END) AS GPContributions
FROM PMTS)as A WHERE GPContributions >0

Resources