Optimize query with nested inner query and case statements - sql-server

I have below query written by someone(Database is Microsoft SQL server 2017). I do not have access to database to create indexes etc., So only way I can do is optimize below query as efficient as possible.
My query here is,
Can I use Case and WHEN in inner query as used in the below query? Also am currently trying to remove nested queries by using inner join.
Any other ideas will be appreciated for the below queries. I am not asking to give final optimized query, but asking suggestion specific to below query.
WITH ChildPremiumCTE (COVER_PREMIUM_SET_ID,POLICY_ID, ADDRESS_ID, STATUS_CODE,COVER_PREMIUM_MODEL_ID, SUB_PRODUCT_REF
, COVER_PREMIUM_MODEL_REF, DESCRIPTION, PREMIUM_LEVEL_CODE
, PREMIUM_PAYABLE, PREMIUM_DUE, COMMISSION_GST, COMMISSION, COMMISSION_TOTAL,TERRORISM_GST
, TERRORISM_RI, STAMP_DUTY, GST, FSL
, MODIFIED_PREMIUM, TECHNICAL_PREMIUM, BASE_PREMIUM
, PREMIUM_PAYABLE_TERM, PREMIUM_DUE_TERM, COMMISSION_GST_TERM
, COMMISSION_TERM, COMMISSION_TOTAL_TERM, TERRORISM_GST_TERM
, TERRORISM_RI_TERM, STAMP_DUTY_TERM, GST_TERM, FSL_TERM
, MODIFIED_PREMIUM_TERM, TECHNICAL_PREMIUM_TERM, BASE_PREMIUM_TERM
, PREMIUM_PAYABLE_ANNUALISED, PREMIUM_DUE_ANNUALISED, COMMISSION_GST_ANNUALISED
, COMMISSION_ANNUALISED, COMMISSION_TOTAL_ANNUALISED, TERRORISM_GST_ANNUALISED
, TERRORISM_RI_ANNUALISED, STAMP_DUTY_ANNUALISED, GST_ANNUALISED
, FSL_ANNUALISED, MODIFIED_PREMIUM_ANNUALISED, TECHNICAL_PREMIUM_ANNUALISED
, BASE_PREMIUM_ANNUALISED)
AS (SELECT CPP.COVER_PREMIUM_SET_ID
, CPS.POLICY_ID
, CASE WHEN CPS.PREMIUM_LEVEL_CODE = 'PREMITEM' THEN SS.ADDRESS_ID ELSE AD.ADDRESS_ID END ADDRESS_ID
, SS.STATUS_CODE
, COALESCE(CPM.COVER_PREMIUM_MODEL_ID, 0) COVER_PREMIUM_MODEL_ID
, CASE WHEN CPS.PREMIUM_LEVEL_CODE = 'POLSUM' THEN 'POLICY_SUMMARY'
ELSE CASE WHEN CPS.PREMIUM_LEVEL_CODE = 'SITSUM' THEN 'SITUATION_SUMMARY' ELSE CPS.SUB_PRODUCT_REF END END SUB_PRODUCT_REF
, CPS.COVER_PREMIUM_MODEL_REF
, CPS.DESCRIPTION
, CPS.PREMIUM_LEVEL_CODE
, MAX(CASE WHEN CPP.PREMIUM_MODEL_PART_REF = 'PREMIUM_PAYABLE' THEN CPP.TRANSACTION_AMOUNT END) PREMIUM_PAYABLE
, MAX(CASE WHEN CPP.PREMIUM_MODEL_PART_REF = 'PREMIUM_DUE' THEN CPP.TRANSACTION_AMOUNT END) PREMIUM_DUE
, MAX(CASE WHEN CPP.PREMIUM_MODEL_PART_REF = 'COMMISSION_GST' THEN CPP.TRANSACTION_AMOUNT END) COMMISSION_GST
, MAX(CASE WHEN CPP.PREMIUM_MODEL_PART_REF = 'COMMISSION' THEN CPP.TRANSACTION_AMOUNT END) COMMISSION
, MAX(CASE WHEN CPP.PREMIUM_MODEL_PART_REF = 'COMMISSION_TOTAL' THEN CPP.TRANSACTION_AMOUNT END) COMMISSION_TOTAL
, MAX(CASE WHEN CPP.PREMIUM_MODEL_PART_REF = 'TERRORISM_GST' THEN CPP.TRANSACTION_AMOUNT END) TERRORISM_GST
, MAX(CASE WHEN CPP.PREMIUM_MODEL_PART_REF = 'TERRORISM_RI' THEN CPP.TRANSACTION_AMOUNT END) TERRORISM_RI
, MAX(CASE WHEN CPP.PREMIUM_MODEL_PART_REF = 'STAMP_DUTY' THEN CPP.TRANSACTION_AMOUNT END) STAMP_DUTY
, MAX(CASE WHEN CPP.PREMIUM_MODEL_PART_REF = 'GST' THEN CPP.TRANSACTION_AMOUNT END) GST
, MAX(CASE WHEN CPP.PREMIUM_MODEL_PART_REF = 'FSL' THEN CPP.TRANSACTION_AMOUNT END) FSL
, MAX(CASE WHEN CPP.PREMIUM_MODEL_PART_REF = 'MODIFIED_PREMIUM' THEN CPP.TRANSACTION_AMOUNT END) MODIFIED_PREMIUM
, MAX(CASE WHEN CPP.PREMIUM_MODEL_PART_REF = 'TECHNICAL_PREMIUM' THEN CPP.TRANSACTION_AMOUNT END) TECHNICAL_PREMIUM
, MAX(CASE WHEN CPP.PREMIUM_MODEL_PART_REF = 'BASE_PREMIUM' THEN CPP.TRANSACTION_AMOUNT END) BASE_PREMIUM
, MAX(CASE WHEN CPP.PREMIUM_MODEL_PART_REF = 'PREMIUM_PAYABLE' THEN CPP.TERM_AMOUNT END) PREMIUM_PAYABLE_TERM
, MAX(CASE WHEN CPP.PREMIUM_MODEL_PART_REF = 'PREMIUM_DUE' THEN CPP.TERM_AMOUNT END) PREMIUM_DUE_TERM
, MAX(CASE WHEN CPP.PREMIUM_MODEL_PART_REF = 'COMMISSION_GST' THEN CPP.TERM_AMOUNT END) COMMISSION_GST_TERM
, MAX(CASE WHEN CPP.PREMIUM_MODEL_PART_REF = 'COMMISSION' THEN CPP.TERM_AMOUNT END) COMMISSION_TERM
, MAX(CASE WHEN CPP.PREMIUM_MODEL_PART_REF = 'COMMISSION_TOTAL' THEN CPP.TERM_AMOUNT END) COMMISSION_TOTAL_TERM
, MAX(CASE WHEN CPP.PREMIUM_MODEL_PART_REF = 'TERRORISM_GST' THEN CPP.TERM_AMOUNT END) TERRORISM_GST_TERM
, MAX(CASE WHEN CPP.PREMIUM_MODEL_PART_REF = 'TERRORISM_RI' THEN CPP.TERM_AMOUNT END) TERRORISM_RI_TERM
, MAX(CASE WHEN CPP.PREMIUM_MODEL_PART_REF = 'STAMP_DUTY' THEN CPP.TERM_AMOUNT END) STAMP_DUTY_TERM
, MAX(CASE WHEN CPP.PREMIUM_MODEL_PART_REF = 'GST' THEN CPP.TERM_AMOUNT END) GST_TERM
, MAX(CASE WHEN CPP.PREMIUM_MODEL_PART_REF = 'FSL' THEN CPP.TERM_AMOUNT END) FSL_TERM
, MAX(CASE WHEN CPP.PREMIUM_MODEL_PART_REF = 'MODIFIED_PREMIUM' THEN CPP.TERM_AMOUNT END) MODIFIED_PREMIUM_TERM
, MAX(CASE WHEN CPP.PREMIUM_MODEL_PART_REF = 'TECHNICAL_PREMIUM' THEN CPP.TERM_AMOUNT END) TECHNICAL_PREMIUM_TERM
, MAX(CASE WHEN CPP.PREMIUM_MODEL_PART_REF = 'BASE_PREMIUM' THEN CPP.TERM_AMOUNT END) BASE_PREMIUM_TERM
, MAX(CASE WHEN CPP.PREMIUM_MODEL_PART_REF = 'PREMIUM_PAYABLE' THEN CPP.FUTURE_ANNUALISED_AMOUNT END) PREMIUM_PAYABLE_ANNUALISED
, MAX(CASE WHEN CPP.PREMIUM_MODEL_PART_REF = 'PREMIUM_DUE' THEN CPP.FUTURE_ANNUALISED_AMOUNT END) PREMIUM_DUE_ANNUALISED
, MAX(CASE WHEN CPP.PREMIUM_MODEL_PART_REF = 'COMMISSION_GST' THEN CPP.FUTURE_ANNUALISED_AMOUNT END) COMMISSION_GST_ANNUALISED
, MAX(CASE WHEN CPP.PREMIUM_MODEL_PART_REF = 'COMMISSION' THEN CPP.FUTURE_ANNUALISED_AMOUNT END) COMMISSION_ANNUALISED
, MAX(CASE WHEN CPP.PREMIUM_MODEL_PART_REF = 'COMMISSION_TOTAL' THEN CPP.FUTURE_ANNUALISED_AMOUNT END) COMMISSION_TOTAL_ANNUALISED
, MAX(CASE WHEN CPP.PREMIUM_MODEL_PART_REF = 'TERRORISM_GST' THEN CPP.FUTURE_ANNUALISED_AMOUNT END) TERRORISM_GST_ANNUALISED
, MAX(CASE WHEN CPP.PREMIUM_MODEL_PART_REF = 'TERRORISM_RI' THEN CPP.FUTURE_ANNUALISED_AMOUNT END) TERRORISM_RI_ANNUALISED
, MAX(CASE WHEN CPP.PREMIUM_MODEL_PART_REF = 'STAMP_DUTY' THEN CPP.FUTURE_ANNUALISED_AMOUNT END) STAMP_DUTY_ANNUALISED
, MAX(CASE WHEN CPP.PREMIUM_MODEL_PART_REF = 'GST' THEN CPP.FUTURE_ANNUALISED_AMOUNT END) GST_ANNUALISED
, MAX(CASE WHEN CPP.PREMIUM_MODEL_PART_REF = 'FSL' THEN CPP.FUTURE_ANNUALISED_AMOUNT END) FSL_ANNUALISED
, MAX(CASE WHEN CPP.PREMIUM_MODEL_PART_REF = 'MODIFIED_PREMIUM' THEN CPP.FUTURE_ANNUALISED_AMOUNT END) MODIFIED_PREMIUM_ANNUALISED
, MAX(CASE WHEN CPP.PREMIUM_MODEL_PART_REF = 'TECHNICAL_PREMIUM' THEN CPP.FUTURE_ANNUALISED_AMOUNT END) TECHNICAL_PREMIUM_ANNUALISED
, MAX(CASE WHEN CPP.PREMIUM_MODEL_PART_REF = 'BASE_PREMIUM' THEN CPP.FUTURE_ANNUALISED_AMOUNT END) BASE_PREMIUM_ANNUALISED
FROM COVER_PREMIUM_SET As CPS
LEFT JOIN SITUATION_SECTION As SS ON CPS.POLICY_ID = SS.POLICY_ID
AND CPS.SITUATION_SECTION_REF = SS.SITUATION_SECTION_REF
LEFT JOIN COVER_PREMIUM_PART As CPP ON CPS.COVER_PREMIUM_SET_ID = CPP.COVER_PREMIUM_SET_ID
LEFT JOIN ADDRESS As AD ON CPS.POLICY_ID = AD.POLICY_ID
AND AD.ADDRESS_REF = CPS.ENTITY_INSTANCE_REF
AND CPS.PREMIUM_LEVEL_CODE IN ('SITSUM', 'SUBPRODSUM')
LEFT JOIN COVER_PREMIUM_MODEL As CPM ON CPS.COVER_PREMIUM_MODEL_REF = CPM.COVER_PREMIUM_MODEL_REF
GROUP BY CPP.COVER_PREMIUM_SET_ID,
CPS.POLICY_ID,
CPS.DESCRIPTION,
CPS.PREMIUM_LEVEL_CODE,
CPS.COVER_PREMIUM_MODEL_REF,
CPS.SUB_PRODUCT_REF,
CPM.COVER_PREMIUM_MODEL_ID,
SS.SITUATION_SECTION_ID,
SS.ADDRESS_ID,
SS.STATUS_CODE,
CPS.ENTITY_INSTANCE_REF,
AD.ADDRESS_ID )
select * from (SELECT
0 AS COVER_PREMIUM_SET_ID
, a1.POLICY_ID
, a1.ADDRESS_ID
, a1.STATUS_CODE
, CPM_CHILD.PARENT_ID AS COVER_PREMIUM_MODEL_ID
, CASE WHEN CPM.PREMIUM_LEVEL_CODE = 'POLSUM' THEN 'POLICY_SUMMARY'
ELSE CASE WHEN CPM.PREMIUM_LEVEL_CODE = 'SITSUM' THEN 'SITUATION_SUMMARY' ELSE a1.SUB_PRODUCT_REF END END SUB_PRODUCT_REF
, CPM.COVER_PREMIUM_MODEL_REF
, CPM.NAME AS Description
, CPM.PREMIUM_LEVEL_CODE AS PREMIUM_LEVEL_CODE
, sum(a1.PREMIUM_PAYABLE) PREMIUM_PAYABLE
, sum(a1.PREMIUM_DUE) PREMIUM_DUE
, sum(a1.COMMISSION_GST) COMMISSION_GST
, sum(a1.COMMISSION) COMMISSION
, sum(a1.COMMISSION_TOTAL) COMMISSION_TOTAL,sum(a1.TERRORISM_GST) TERRORISM_GST
, sum(a1.TERRORISM_RI) TERRORISM_RI, sum(a1.STAMP_DUTY) STAMP_DUTY,sum(a1.GST ) GST, sum(a1.FSL ) FSL
, sum(a1.MODIFIED_PREMIUM ) MODIFIED_PREMIUM, sum(a1.TECHNICAL_PREMIUM ) TECHNICAL_PREMIUM, sum(a1.BASE_PREMIUM ) BASE_PREMIUM
, sum(a1.PREMIUM_PAYABLE_TERM) PREMIUM_PAYABLE_TERM, sum(a1.PREMIUM_DUE_TERM ) PREMIUM_DUE_TERM
, sum(a1.COMMISSION_GST_TERM ) COMMISSION_GST_TERM, sum(a1.COMMISSION_TERM ) COMMISSION_TERM
, sum(a1.COMMISSION_TOTAL_TERM ) COMMISSION_TOTAL_TERM, sum(a1.TERRORISM_GST_TERM ) TERRORISM_GST_TERM
, sum(a1.TERRORISM_RI_TERM ) TERRORISM_RI_TERM, sum(a1.STAMP_DUTY_TERM ) STAMP_DUTY_TERM
, sum(a1.GST_TERM ) GST_TERM, sum(a1.FSL_TERM ) FSL_TERM, sum(a1.MODIFIED_PREMIUM_TERM ) MODIFIED_PREMIUM_TERM
, sum(a1.TECHNICAL_PREMIUM_TERM ) TECHNICAL_PREMIUM_TERM, sum(a1.BASE_PREMIUM_TERM ) BASE_PREMIUM_TERM
, sum(a1.PREMIUM_PAYABLE_ANNUALISED) PREMIUM_PAYABLE_ANNUALISED, sum(a1.PREMIUM_DUE_ANNUALISED ) PREMIUM_DUE_ANNUALISED
, sum(a1.COMMISSION_GST_ANNUALISED ) COMMISSION_GST_ANNUALISED, sum(a1. COMMISSION_ANNUALISED ) COMMISSION_ANNUALISED
, sum(a1. COMMISSION_TOTAL_ANNUALISED ) COMMISSION_TOTAL_ANNUALISED, sum(a1.TERRORISM_GST_ANNUALISED ) TERRORISM_GST_ANNUALISED
, sum(a1.TERRORISM_RI_ANNUALISED ) TERRORISM_RI_ANNUALISED, sum(a1.STAMP_DUTY_ANNUALISED ) STAMP_DUTY_ANNUALISED
, sum(a1.GST_ANNUALISED ) GST_ANNUALISED, sum(a1.FSL_ANNUALISED ) FSL_ANNUALISED
, sum(a1.MODIFIED_PREMIUM_ANNUALISED ) MODIFIED_PREMIUM_ANNUALISED
, sum(a1.TECHNICAL_PREMIUM_ANNUALISED ) TECHNICAL_PREMIUM_ANNUALISED
, sum(a1.BASE_PREMIUM_ANNUALISED) BASE_PREMIUM_ANNUALISED
FROM COVER_PREMIUM_MODEL CPM,
COVER_PREMIUM_MODEL CPM_CHILD,
ChildPremiumCTE a1
WHERE
CPM.PREMIUM_LEVEL_CODE = 'PREMRLUP'
AND CPM_CHILD.PARENT_ID = CPM.COVER_PREMIUM_MODEL_ID
AND CPM_CHILD.COVER_PREMIUM_MODEL_REF = a1.COVER_PREMIUM_MODEL_REF
GROUP BY
a1.POLICY_ID,
a1.ADDRESS_ID,
CPM_CHILD.PARENT_ID,
CPM.NAME,
CPM.PREMIUM_LEVEL_CODE,
a1.SUB_PRODUCT_REF,
CPM.COVER_PREMIUM_MODEL_REF,
a1.STATUS_CODE
UNION ALL
select * from ChildPremiumCTE) CoverPremium where CoverPremium.POLICY_ID = 77780029
So far what I have improved is,
Made union to union all
Trying to convert subqueries into where clause
built in functions like MAX, SUM to like string literal

First suggestion is same as #LukStorms.Also always use alias of table and prefix them in column so that it is very easy to understand and debug.
Can I use Case and WHEN in inner query as used in the below query?
Everything has cost.It seem that in this case cost is negligible.
Any other ideas will be appreciated for the below queries. I am not
asking to give final optimized query, but asking suggestion specific
to below query.
GROUP BY on All column is always bad idea.First Using CTE or #Temp table
write Group By query using only require table and Group By on Key column only.
Suppose you need some other column also which is not part of aggregate or Group By,then no problem don't try to use that column here.
Join the same table in main query to get those columns which is not part of aggregate.
Then in Main query again join that CTE or temp table with other table.
This is how you should design your query .
PREMIUM_MODEL_PART_REF and TRANSACTION_AMOUNT belong to which table ?
Table COVER_PREMIUM_MODEL are use 3 times in query.Put the require data of COVER_PREMIUM_MODEL on #temp table .There must be some common result in all three join.
Excerpt
select * from (Select * blah blah
UNION ALL
select * from ChildPremiumCTE) a2 where a2.POLICY_ID = 77780029
WHY use where POLICY_ID = 77780029 in the end ?
This way first so many rows will be process in inner query then finally reduce to POLICY_ID = 77780029.
So WHY not use POLICY_ID = 77780029 in inner query somewhere in the first place.
built in functions like MAX, SUM to like string literal
It depend what type of UDF it is and what you have written in it.
In short UDF are notoriously Bad Perform-ant most of the time.
It do not appear to be that MAX, SUM need UDF.

Related

Repeat Case Functions Used to Transpose

With the help from another poster, I developed the following code:
Select a.[PT_FIN]
,[RESULT_DT_TM1] = max(case when RN=1 then [RESULT_DT_TM] end)
,[Weight1] = max(case when RN=1 then [WEIGHT_RESULT] end)
,[Sysbp1] = max(case when RN=1 then [SYSBP_RESULT] end)
,[DiaBP1] = max(case when RN=1 then [DIABP_RESULT] end)
,[Temp1] = max(case when RN=1 then [TEMPERATURE_RESULT] end)
,[Oxy1] = max(case when RN=1 then [OXYGEN_SAT_RESULT] end)
,[Fio1] = max(case when RN=1 then [FIO2_RESULT] end)
,[Flow1] = max(case when RN=1 then [Flow_Rate_Result] end)
,[RESULT_DT_TM2] = max(case when RN=1 then [RESULT_DT_TM] end)
,[Weight2] = max(case when RN=1 then [Weight] end)
,[Sysbp2] = max(case when RN=1 then [Sysbp] end)
,[DiaBP2] = max(case when RN=1 then [DiaBP] end)
,[Temp2] = max(case when RN=1 then [TEMPERATURE_RESULT] end)
,[Oxy2] = max(case when RN=1 then [OXYGEN_SAT_RESULT] end)
,[Fio2] = max(case when RN=1 then [FIO2_RESULT] end)
,[Flow2] = max(case when RN=1 then [Flow_Rate_Result] end)
ETC
Each number at the end of the variable corresponds to a row a subject may have data (some subjects have 1 row of data, some may have 10). Is there an efficient way to repeat this code to capture a max of 10 rows of data so I do not have to add for example:
[RESULT_DT_TM3]= max(case when RN=3 then [RESULT_DT_TM] end)
[Weight3]= max(case when RN=3 then [WEIGHT_RESULT] end)
[RESULT_DT_TM4] = max(case when RN=4 then [RESULT_DT_TM] end)
[Weight4]= max(case when RN=4 then [Weight_Result] end)
....

Subquery a Cast Function

I have the following code which I'm using to transpose some data (see below); however, when running the code I received a 'Operand data type datetime2 is invalid for sum operator' error, which I believe is due to the fact the [RESULT_DT_TM] column has both date and time values. With the help from the outstanding contributors, I made what turns out to be a very simple code that removes the date from the [RESULT_DT_TM]:
select cast([RESULT_DT_TM] as time (0)) as [result_dt]
from ED_Vitals_Import_Master
I would like to include this code within the main query so I have use the new [result_dt] variable but am having trouble embedding it. Is it possible to do what I am seeking?
Select *
From (
Select a.[PT_FIN]
,B.*
From (Select *,RN=Row_Number() over (Partition By PT_FIN Order by [RESULT_DT_TM]) From ED_Vitals_Import_Master ) A
Cross Apply (values (concat('Time' ,RN),[RESULT_DT_TM])
,(concat('Weight' ,RN),[WEIGHT_RESULT])
,(concat('SysBp' ,RN),[SYSBP_RESULT])
,(concat('DiaBP',RN),[DIABP_RESULT])
,(concat('Temp' ,RN),[TEMPERATURE_RESULT])
,(concat('Oxy' ,RN),[OXYGEN_SAT_RESULT])
,(concat('Fio' ,Rn),[FIO2_RESULT])
) B(Item,Value)
) src
Pivot (sum(Value) for Item in ([RESULT_DT_TM1],[Weight1],[Sysbp1],[DiaBP1], [Temp1], [Oxy1], [Fio1]
,[RESULT_DT_TM2],[Weight2],[Sysbp2],[DiaBP2], [Temp2], [Oxy2], [Fio2]
,[RESULT_DT_TM3],[Weight3],[Sysbp3],[DiaBP3], [Temp3], [Oxy3], [Fio3]
,[RESULT_DT_TM4],[Weight4],[Sysbp4],[DiaBP4], [Temp4], [Oxy4], [Fio4]
) ) pvt
Since you are mixing datatypes... perhaps a conditional aggregation would be more useful.
Example
Select a.[PT_FIN]
,[RESULT_DT_TM1] = max(case when RN=1 then [RESULT_DT_TM] end)
,[Weight1] = max(case when RN=1 then [Weight] end)
,[Sysbp1] = max(case when RN=1 then [Sysbp] end)
,[DiaBP1] = max(case when RN=1 then [DiaBP] end)
,[Temp1] = max(case when RN=1 then [Temp] end)
,[Oxy1] = max(case when RN=1 then [Oxy] end)
,[Fio1] = max(case when RN=1 then [Fio] end)
,[RESULT_DT_TM2] = max(case when RN=2 then [RESULT_DT_TM] end)
,[Weight2] = max(case when RN=2 then [Weight] end)
,[Sysbp2] = max(case when RN=2 then [Sysbp] end)
,[DiaBP2] = max(case when RN=2 then [DiaBP] end)
,[Temp2] = max(case when RN=2 then [Temp] end)
,[Oxy2] = max(case when RN=2 then [Oxy] end)
,[Fio2] = max(case when RN=2 then [Fio] end)
--- Extend the Groups Here ---
From (Select *,RN=Row_Number() over (Partition By PT_FIN Order by [RESULT_DT_TM]) From ED_Vitals_Import_Master ) A
Group By a.[PT_FIN]

Convert vertical table to horizontal in SQL Server

I have a large table that has 8 row numbers with an associated loss and carrier. I am trying to convert into a horizontal structure.
CREATE TABLE #mytable
(
[ID] int NULL,
[RowNum] bigint NULL,
[Loss] float NULL,
[Carrier] nvarchar(255) NULL
)
INSERT INTO #mytable ([ID], [RowNum], [Loss], [Carrier])
VALUES (1,1, 0, 'test1'),
(1,2, NULL, 'test2'),
(1,3, 1.95, 'test3'),
(1,4, 51, 'test4'),
(1,5, 105.75, 'test5'),
(1,6, 0, 'test6'),
(1,7, 173, 'test7'),
(1,8, 256.35, 'test8'),
(2,1, 33158.3, 'test1'),
(2,2, 7925396, 'test2'),
(2,3, 0, 'test3'),
(2,4, NULL, 'test4'),
(2,5, 2461684, 'test5'),
(2,6, 159392, 'test6'),
(2,7, 14791, 'test7'),
(2,8, 14555, 'test8');
I am trying to get a horizontal table like the following (per id and a horizontal structure for Loss and Carrier):
I was trying case when end statements, but I wasn't achieving the desired results.
Can someone please help? I appreciate it.
This has been asked and answered hundreds of times. But it was easier to code a solution than point you to a duplicate. Excellent job posting table structure, sample data and desired output!!!
The easiest solution is using conditional aggregation like this.
select ID
, Loss1 = max(case when RowNum = 1 then Loss end)
, Loss2 = max(case when RowNum = 2 then Loss end)
, Loss3 = max(case when RowNum = 3 then Loss end)
, Loss4 = max(case when RowNum = 4 then Loss end)
, Loss5 = max(case when RowNum = 5 then Loss end)
, Loss6 = max(case when RowNum = 6 then Loss end)
, Loss7 = max(case when RowNum = 7 then Loss end)
, Loss8 = max(case when RowNum = 8 then Loss end)
, Carrier1 = max(case when RowNum = 1 then Carrier end)
, Carrier2 = max(case when RowNum = 2 then Carrier end)
, Carrier3 = max(case when RowNum = 3 then Carrier end)
, Carrier4 = max(case when RowNum = 4 then Carrier end)
, Carrier5 = max(case when RowNum = 5 then Carrier end)
, Carrier6 = max(case when RowNum = 6 then Carrier end)
, Carrier7 = max(case when RowNum = 7 then Carrier end)
, Carrier8 = max(case when RowNum = 8 then Carrier end)
from #mytable
group by ID

SQL error message - Incorrect syntax near ')'

I get this error message
"Incorrect syntax near ')'."
from the sum(PayHours) line and I would appreciate a bit of guidance on how to go about solving it. I am stuck.
[#PremierThree] from code below is a temporary table being created on the fly and drop afterwards
SELECT *
FROM [#PremierThree]
PIVOT
(SUM(PayHours)
FOR [Pay_ClassHrs] IN ([PBS_Hrs], [POT_Hrs], [PED_Hrs], [POR_Hrs], [Agency_Hrs], [PWH_Hrs], [Sick_Hrs], [PTO_Hrs], [Holiday_Hrs], [PJB_Hrs], [Bugeted_Work_Hrs], [Bugeted_Benefit_Hrs])
) AS pvt1
PIVOT
(SUM(PayAmount)
FOR [Pay_Class$] in ([PBS_$], [POT_$], [PED_$], [POR_$], [Agency_$], [PWH_$], [Sick_$], [PTO_$], [Holiday_$], [PJB_$], [PNH_$],[Bugeted_Work_$], [Bugeted_Benefit_$])
) AS pvt2
ORDER BY
[Facility], CAST([Job_Code] AS INT)
A pivot query does not contain 2 or more pivot clauses in T-SQL see FROM - Using PIVOT and UNPIVOT
You are attempting to output Hours and Dollars as "2 column sets" and frankly I find the T-SQL implementation of pivot too limiting for that. You could try an approach of using unpivot and pivot together to get the effect you want (example here).
Personally I would go for a more traditional style of pivot query that simply uses GROUP BY and case expressions as necessary (the style we always had to use before "pivot was added to SQL at all). e.g. (but I leave the column aliases up to you)
SELECT
[Facility]
, [Job_Code]
, SUM(CASE WHEN Pay_ClassHrs = 'PBS_Hrs' THEN Pay_ClassHrs END) AS x
, SUM(CASE WHEN Pay_ClassHrs = 'POT_Hrs' THEN Pay_ClassHrs END) AS x
, SUM(CASE WHEN Pay_ClassHrs = 'PED_Hrs' THEN Pay_ClassHrs END) AS x
, SUM(CASE WHEN Pay_ClassHrs = 'POR_Hrs' THEN Pay_ClassHrs END) AS x
, SUM(CASE WHEN Pay_ClassHrs = 'Agency_Hrs' THEN Pay_ClassHrs END) AS x
, SUM(CASE WHEN Pay_ClassHrs = 'PWH_Hrs' THEN Pay_ClassHrs END) AS x
, SUM(CASE WHEN Pay_ClassHrs = 'Sick_Hrs' THEN Pay_ClassHrs END) AS x
, SUM(CASE WHEN Pay_ClassHrs = 'PTO_Hrs' THEN Pay_ClassHrs END) AS x
, SUM(CASE WHEN Pay_ClassHrs = 'Holiday_Hrs' THEN Pay_ClassHrs END) AS x
, SUM(CASE WHEN Pay_ClassHrs = 'PJB_Hrs' THEN Pay_ClassHrs END) AS x
, SUM(CASE WHEN Pay_ClassHrs = 'Bugeted_Work_Hrs' THEN Pay_ClassHrs END) AS x
, SUM(CASE WHEN Pay_ClassHrs = 'Bugeted_Benefit_Hrs' THEN Pay_ClassHrs END) AS x
, SUM(CASE WHEN Pay_Class$ = 'POT_$' THEN Pay_Class$ END) AS x
, SUM(CASE WHEN Pay_Class$ = 'PED_$' THEN Pay_Class$ END) AS x
, SUM(CASE WHEN Pay_Class$ = 'POR_$' THEN Pay_Class$ END) AS x
, SUM(CASE WHEN Pay_Class$ = 'Agency_$' THEN Pay_Class$ END) AS x
, SUM(CASE WHEN Pay_Class$ = 'PWH_$' THEN Pay_Class$ END) AS x
, SUM(CASE WHEN Pay_Class$ = 'Sick_$' THEN Pay_Class$ END) AS x
, SUM(CASE WHEN Pay_Class$ = 'PTO_$' THEN Pay_Class$ END) AS x
, SUM(CASE WHEN Pay_Class$ = 'Holiday_$' THEN Pay_Class$ END) AS x
, SUM(CASE WHEN Pay_Class$ = 'PJB_$' THEN Pay_Class$ END) AS x
, SUM(CASE WHEN Pay_Class$ = 'PNH_$' THEN Pay_Class$ END) AS x
, SUM(CASE WHEN Pay_Class$ = 'Bugeted_Work_$' THEN Pay_Class$ END) AS x
, SUM(CASE WHEN Pay_Class$ = 'Bugeted_Benefit_$' THEN Pay_Class$ END) AS x
FROM [#PremierThree]
GROUP BY
[Facility]
, [Job_Code]
UNTESTED!
If the above approach looks too old hat and wordy for you. Try combining the 2 pivots using a join, below I have assumed it would need a full outer join but it might work with a simpler inner join if both subqueries produce the same rows (which is quite likely in your case using that temp table).
SELECT
COALESCE(p1.Facility,p2.Facility) Facility
, COALESCE(p1.Job_Code,p2.Job_Code) Job_Code
, [PBS_Hrs], [POT_Hrs], [PED_Hrs], [POR_Hrs], [Agency_Hrs], [PWH_Hrs], [Sick_Hrs], [PTO_Hrs], [Holiday_Hrs], [PJB_Hrs], [Bugeted_Work_Hrs], [Bugeted_Benefit_Hrs]
, [PBS_$], [POT_$], [PED_$], [POR_$], [Agency_$], [PWH_$], [Sick_$], [PTO_$], [Holiday_$], [PJB_$], [PNH_$],[Bugeted_Work_$], [Bugeted_Benefit_$]
FROM (
SELECT
[Facility]
, [Job_Code]
, [PBS_Hrs], [POT_Hrs], [PED_Hrs], [POR_Hrs], [Agency_Hrs], [PWH_Hrs], [Sick_Hrs], [PTO_Hrs], [Holiday_Hrs], [PJB_Hrs], [Bugeted_Work_Hrs], [Bugeted_Benefit_Hrs]
FROM [#PremierThree]
PIVOT
(SUM(PayHours)
FOR [Pay_ClassHrs] IN ([PBS_Hrs], [POT_Hrs], [PED_Hrs], [POR_Hrs], [Agency_Hrs], [PWH_Hrs], [Sick_Hrs], [PTO_Hrs], [Holiday_Hrs], [PJB_Hrs], [Bugeted_Work_Hrs], [Bugeted_Benefit_Hrs])
) AS pvt1
) AS p1
FULL OUTER JOIN (
SELECT
[Facility]
, [Job_Code]
, [PBS_$], [POT_$], [PED_$], [POR_$], [Agency_$], [PWH_$], [Sick_$], [PTO_$], [Holiday_$], [PJB_$], [PNH_$],[Bugeted_Work_$], [Bugeted_Benefit_$]
PIVOT
(SUM(PayAmount)
FOR [Pay_Class$] in ([PBS_$], [POT_$], [PED_$], [POR_$], [Agency_$], [PWH_$], [Sick_$], [PTO_$], [Holiday_$], [PJB_$], [PNH_$],[Bugeted_Work_$], [Bugeted_Benefit_$])
) AS pvt2
) AS p2
ON p1.Facility = p2.Facility AND p1.Job_Code = p2.Job_Code
ORDER BY
[Facility], CAST([Job_Code] AS INT)
;
For T-SQL: Personally, even with a join approach I don't see any advantage to using pivot when it starts to get complex.

XML won't output Divide by zero encountered in SQL Query

I have a Query that selects Election data. Of course, when you start an election, there are 0 votes input for all candidates. But gradually, votes get entered. In order to get the percentage to output from the results, I took, number of votes multiplied by 100 then divided by total votes and I got my percentage.
Problem- once my query runs for the xml path, there is an error written in the top line of the xml document, "Divide by Zero error encountered". In order to bypass this, I just commented out the divide lines, but I would not like to do that. I figured, if I waited until there was a race that had votes in each field, I would then un-comment that line of code and let it output the percentage of only that race....until ALL races had at least some votes within them.
Here is my sql code:
:XML ON
select
max(case when seqnum = 1 then title1 end) as title1,
max(case when seqnum = 1 then [precinct percent] end) as PrecinctPercent,
max(case when seqnum = 1 then [candidate num] end) as WinnerNum,
max(case when seqnum = 1 then Votes end) as WinningVotes,
max(case when seqnum = 1 then party end) as WinningParty,
max(case when seqnum = 1 then leader end) as Winner,
max(case when seqnum = 1 then CAST(winner AS tinyint) end) as WinnerSelected,
max(case when seqnum = 1 then ((Votes * 100) / ([total vote])) end) as WinnerPercent,
max(case when seqnum = 2 then [candidate num] end) as LoserNum,
max(case when seqnum = 2 then Votes end) as LosingVotes,
max(case when seqnum = 2 then party end) as LosingParty,
max(case when seqnum = 2 then leader2 end) as Loser,
max(case when seqnum = 2 then ((Votes * 100) / ([total vote])) end) as LoserPercent,
max(case when seqnum = 2 then CAST(winner AS tinyint) end) as LoserSelected,
max(case when seqnum = 3 then title1 end) as title1,
max(case when seqnum = 3 then [precinct percent] end) as PrecinctPercent,
max(case when seqnum = 3 then [candidate num] end) as WinnerNum,
max(case when seqnum = 3 then Votes end) as WinningVotes,
max(case when seqnum = 3 then ((Votes * 100) / ([total vote])) end) as WinnerPercent,
max(case when seqnum = 3 then party end) as WinningParty,
max(case when seqnum = 3 then [first name]+ ' ' + [last name] end) as Winner,
max(case when seqnum = 3 then CAST(winner AS tinyint) end) as WinnerSelected,
max(case when seqnum = 4 then [precinct percent] end) as PrecinctPercent,
max(case when seqnum = 4 then [candidate num] end) as LoserNum,
max(case when seqnum = 4 then Votes end) as LosingVotes,
max(case when seqnum = 4 then ((Votes * 100) / ([total vote])) end) as LoserPercent,
max(case when seqnum = 4 then party end) as LosingParty,
max(case when seqnum = 4 then [first name]+ ' ' + [last name] end) as Loser,
max(case when seqnum = 4 then CAST(winner AS tinyint) end) as LoserSelected
from
(
select
r.title1,
r.[precinct percent],
r.[total vote],
rc.[race number],
rc.[candidate num],
rc.[Votes],
rc.[winner],
c.[party],
r.[leader],
r.[leader percent],
r.[leader2],
r.[leader2 percent],
c.[first name],
c.[last name],
row_number() over (partition by rc.[race number] order by votes desc) as seqnum
from dbo.[RACE CANDIDATES] rc
inner join dbo.[CANDIDATE] c on rc.[candidate num] = c.[candidate number]
inner join dbo.[RACE] r
on rc.[race number] = r.[race number]
) rc
group by rc.[race number]
FOR XML PATH ('ELECTION'), ROOT('root')
Is there a way I can have the select statement just "IGNORE" any fields that contain 0. Or choose to omit those that do contain 0 votes.
The total number of votes are being selected from the table "[RACE CANDIDATES]" if that helps. Hope it all makes sense.
Any input would be greatly appreciated.
Thanks All!
You can either put in a where in the sub select
WHERE r.[total vote] != 0
or you could use a case statment
CASE WHEN r.[total vote] = 0 THEN 0 ELSE Votes / r.[total vote] END

Resources