pyspark sql jdbc error - Incorrect syntax near the keyword 'SET' - sql

Following is the SQL Sample which Im trying to run, but its is giving me error - ***.jdbc.SQLServerException: Incorrect syntax near the keyword 'SET'
tp_temp = """
SET NOCOUNT ON
declare #lp_dt dt = (select max(pt_dt) from [DB_TABLE].[db].[DATA] where p_type='WSD')
declare #L_dte tb (pt, pt_type char(1))
insert into #L_dte SELECT pt_dt, pt_type
FROM from [DB_TABLE].[db].[DATA]
where (PT_Type = 'Z' and Month(pt_dt) in (1,4,7,10) and pt_dt > '2017 Sep 1') or (PT_Type = 'K' and pt_dt = #lp_dt )
group by pt_dt, PT_Type
order by pt_dt
SELECT z_id_alt, z_id, z_Status_Alt, c_Gp_CCD, Gender, Age, ctk as CTK_Red, CAT_Title, temp_Group, Comp_price, terminator_action_alt AS Terminator_Action, v_pt.PT_Dt,CASE
WHEN COALESCE([Acb_Indicator], '') = ''
THEN ('No')
ELSE ('Yes')
END AS [Is Acb],
COALESCE(nullif([Region_Desc_NEWCO_Original], ''), Region_Desc_NEWCO) AS Region_Desc_NEWCO,
COALESCE(nullif([POG3_Desc_Original], ''), POG3_Desc) AS POG3_Desc,
COALESCE(nullif([POG9_Desc_Original], ''), POG9_Desc) AS POG9_Desc, COALESCE(nullif(BSD_Function, ''), OrgUnit_Function_L2_NEWCO) as OrgUnit_Function_L2_NEWCO, CASE
WHEN COALESCE(nullif([POG3_Desc_Original], ''), POG3_Desc) IN (
SELECT [POG_Desc]
FROM [DB_FREE].[dbz].[Free_dom]
WHERE POG_Type = 'POG3'
)
OR COALESCE(nullif([POG9_Desc_Original], ''), POG9_Desc) IN (
SELECT [POG_Desc]
FROM [DB_FREE].[dbz].[Free_dom]
WHERE POG_Type = 'POG9'
)
THEN 'Yes'
ELSE 'No'
END AS [Restricted_Home], Zero) AS Booring
FROM (SELECT * FROM [DB_FREE].[dbz].[Free_dom] WHERE noshow = 'N' AND E_Type <> 'SubConsole') as v_pt
INNER JOIN #l_pt_dt as pt_dt on v_pt.pt_dt = pt_dt.pt_dt and v_pt.pt_type = pt_dt.pt_type
LEFT OUTER JOIN [DB_TABLE].[db].[DATA] AS o_p ON o_p.[u_number] = v_pt.ete_idg """
df_temp= spark.read.jdbc(url=jdbcUrl, table=tp_temp, properties=connectionProperties)
For simple SQL starting with Select command it works but for code starting with SET or WITH it throws errors, please let me know how I can create a table from this SQL code in pyspark dataframe

Related

Running a query with cast and alias - not working

I have this query I am trying to run, and I keep getting an error. Could be somethign related to the alias, but I think this seems correct?
SELECT user_key, playerslevel
FROM data_lab.vw_ft_Game_Progression a
INNER JOIN data_lab.vw_progress b on a.rock_key = b.rock_key
WHERE user_key = 21111119 AND type = 'Level'
AND (CAST(REGEXP_REPLACE(game_progression, 'LEVEL ', '') as INTEGER)) as playerslevel < 15
ERROR: Executed as Single statement. Failed [3707 : 42000] Syntax error, expected something like a 'SUCCEEDS' keyword or a 'MEETS' keyword or a 'PRECEDES' keyword or an 'IN' keyword or a 'CONTAINS' keyword between ')' and the 'as' keyword.
Do you know how I can fix this?
Just get rid of as playerslevel. You do not need to alias it in your WHERE clause.
Result:
SELECT
user_key,
playerslevel
FROM
data_lab.vw_ft_Game_Progression a
INNER JOIN
data_lab.vw_progress b
ON
a.rock_key = b.rock_key
WHERE
user_key = 21111119
AND type = 'Level'
AND (CAST(REGEXP_REPLACE(game_progression, 'LEVEL ', '') as INTEGER)) < 15;
Based on your comment
If you just want to get the number you can do this:
DECLARE #test_level VARCHAR(50) = (SELECT 'Level 15');
DECLARE #int_pos INT = (SELECT CHARINDEX(' ', #test_level, 0));
SELECT #int_pos;
SELECT CAST(SUBSTRING(#test_level, #int_pos, LEN(#test_level)-1) AS INT);
So in your case you can do:
SELECT
user_key,
playerslevel
FROM
data_lab.vw_ft_Game_Progression a
INNER JOIN
data_lab.vw_progress b
ON
a.rock_key = b.rock_key
WHERE
user_key = 21111119
AND [type] = 'Level'
AND CAST(SUBSTRING(game_progression, CHARINDEX(' ', game_progression, 0), LEN(game_progression)-1) AS INT) < 15;

Execute string contained in a column in SQL Server

I need to execute a query contained in a string column in SQL Server; how can I do that?
I need to update a column with the result of the query contained in sql_text:
The query that generates that is:
id_coordenadaGPS,
CONCAT('UPDATE CoordenadaGPS SET ogr_geometry = geometry::',
( CASE poly_type
WHEN 'POLYGON' THEN 'STPolyFromText'
WHEN 'LINESTRING' THEN 'STLineFromText'
ELSE 'STPointFromText'
END ),
'("', poly_string, '", 4326) WHERE id = ', id_coordenadaGPS) as sql_text
FROM (
SELECT CONCAT(poly_type, '(', point, ')') as poly_string, Id_CoordenadaGPS, poly_type FROM (
SELECT
(CASE
WHEN y.TOTAL_POINTS = 1 THEN 'POINT'
WHEN y.TOTAL_POINTS >= 3 THEN
CASE WHEN y.first_point = y.last_point THEN 'POLYGON' ELSE 'LINESTRING' END
ELSE 'LINE'
END) as poly_type,
point,
Id_CoordenadaGPS
FROM (
SELECT STRING_agg( CAST(CONCAT(Latitud,' ', Longitud) as nvarchar(max)), ',') as point, Id_CoordenadaGPS, count(1) AS TOTAL_POINTS,
(SELECT TOP 1 CONCAT(Latitud,' ', Longitud) FROM puntoGPS WHERE Id_CoordenadaGPS = x.Id_CoordenadaGPS AND Orden = 1) as first_point,
(SELECT TOP 1 CONCAT(Latitud,' ', Longitud) FROM puntoGPS WHERE Id_CoordenadaGPS = x.Id_CoordenadaGPS AND Orden = (SELECT TOP 1 Orden
FROM puntoGPS WHERE Id_CoordenadaGPS = x.Id_CoordenadaGPS ORDER BY Orden DESC )) as last_point
FROM (
SELECT TOP 1000000 latitud, longitud, id_CoordenadaGPS, Orden FROM puntoGPS
WHERE Id_CoordenadaGPS IN (
SELECT Id FROM CoordenadaGPS
)
ORDER BY orden
) x
GROUP BY Id_CoordenadaGPS
) y
) z
) FIN
PuntosGPS
Table with vertex coordinates, draw order and ID of the entity with corresponds.
CoordenadasGPS
Table with ID , type of geometry and Name of each entity.
I need to create a ogr_geometry column in this table with the vertex information contained in PuntoGPS table.
If anyone has a "good way" to do all in one query would be awesome!
Thanks to all
Try this:
declare #Sql_text as varchar(1000)
Select #Sql_text = Sql_text from your table where idcordonadaGPS = 222
exec(#Sql_text)

How to specify multiple values in when using case statement in sql server

I have the following table
Id Number TypeOfChange
1 2X Scope,Cost,Schedule,EVM,PA
2 3x Scope,Cost
Expected output:
Id Number TypeOfChange Scope Cost Schedule EVM PA
1 2X Scope,Cost,Schedule,EVM,PA X X X X X
2 3x Scope,Cost X X
I try the following script but its not working
SELECT
Id,
Number,
TypeOfChange,
Scope = CASE
WHEN TypeOfChange = 'Scope' THEN 'X'
ELSE '' END,
Cost = CASE
WHEN TypeOfChange = 'Cost' THEN 'X'
ELSE '' END,
Schedule = CASE
WHEN TypeOfChange = 'Schedule' THEN 'X'
ELSE '' END,
EVM = CASE
WHEN TypeOfChange = 'EVM' THEN 'X'
ELSE '' END,
PA = CASE
WHEN TypeOfChange = 'PA' THEN 'X'
ELSE '' END
FROM A
Use Like operator.
SELECT
Id,
Number,
TypeOfChange,
Scope = CASE
WHEN TypeOfChange Like '%Scope%' THEN 'X'
ELSE '' END,
Cost = CASE
WHEN TypeOfChange Like '%Cost%' THEN 'X'
ELSE '' END,
Schedule = CASE
WHEN TypeOfChange Like '%Schedule%' THEN 'X'
ELSE '' END,
EVM = CASE
WHEN TypeOfChange Like '%EVM%' THEN 'X'
ELSE '' END,
PA = CASE
WHEN TypeOfChange Like '%PA%' THEN 'X'
ELSE '' END
FROM A
Example:
we can try charindex or patindex
SELECT
Id,
Number,
TypeOfChange,
Scope = CASE
WHEN CHARINDEX('Scope',TypeOfChange)>0 THEN 'X'
ELSE '' END,
Cost = CASE
WHEN CHARINDEX('Cost',TypeOfChange)>0 THEN 'X'
ELSE '' END,
Schedule = CASE
WHEN CHARINDEX('Schedule',TypeOfChange)>0 THEN 'X'
ELSE '' END,
EVM = CASE
WHEN CHARINDEX('EVM',TypeOfChange)>0 THEN 'X'
ELSE '' END,
PA = CASE
WHEN CHARINDEX('PA',TypeOfChange)>0 THEN 'X'
ELSE '' END
FROM #AA
output
Id Number TypeOfChange Scope Cost Schedule EVM PA
1 2X Scope,Cost,Schedule,EVM,PA X X X X X
2 3x Scope,Cost X X
If TypeOfChange is a dynamic value, you may want to go the dynamic route.
select * into [T1] from
(values (1, '2X', 'Scope,Cost,Schedule,EVM,PA'), (2, '3x', 'Scope,Cost'), (3, '4x', 'someOtherType')) t(Id, Number, TypeOfChange)
--typeOfChange into column list
Declare #SQL varchar(max) = Stuff((
SELECT distinct ',' + QuoteName(LTRIM(RTRIM(m.n.value('.[1]','varchar(8000)'))))
FROM ( SELECT CAST('<XMLRoot><RowData>' + REPLACE(TypeOfChange,',','</RowData><RowData>') + '</RowData></XMLRoot>' AS XML) AS x
FROM [T1]) t CROSS APPLY x.nodes('/XMLRoot/RowData')m(n)
Order by 1 For XML Path('')),1,1,'')
Select #SQL = '
Select [Id],[Number], [TypeOfChange],' + #SQL + '
From (
SELECT Id, Number, TypeOfChange,
LTRIM(RTRIM(m.n.value(''.[1]'',''varchar(8000)''))) AS [Type], ''X'' as Value
FROM ( SELECT Id, Number, TypeOfChange, CAST(''<XMLRoot><RowData>'' + REPLACE(TypeOfChange,'','',''</RowData><RowData>'') + ''</RowData></XMLRoot>'' AS XML) AS x
FROM [T1]) t CROSS APPLY x.nodes(''/XMLRoot/RowData'')m(n)
) A
Pivot (max(Value) For [Type] in (' + #SQL + ') ) pvt'
Exec(#SQL);
Alternatively you may want to define your Types in a lookup table
select * into [Types] from
(values (1, 'Scope'), (2, 'Cost'), (3, 'Schedule'), (4, 'EVM'), (5, 'PA'), (6, 'someOtherType')) a (Id, TypeOfChange)
Then change the above --typeOfChange into column.. block like this:
--typeOfChange into column list
Declare #SQL varchar(max) = Stuff((
SELECT distinct ',' + QuoteName(TypeOfChange)
FROM [Types]
Order by 1 For XML Path('')),1,1,'')
I think, using LIKE is wrong approach. Especcialy in cases, when one of your strings become f.e."Periscope". You will get false positives.
Try to create user defined function to split strs:
CREATE FUNCTION [dbo].[str__split](
#str NVARCHAR(MAX)
,#delimiter NVARCHAR(MAX)
)
RETURNS #split TABLE(
[str] NVARCHAR(MAX)
)
AS
BEGIN
INSERT INTO #split(
[str]
)
SELECT
[X].[C].[value]('(./text())[1]', 'nvarchar(4000)')
FROM
(
SELECT
[X] = CONVERT(XML, '<i>' + REPLACE(#str, #delimiter, '</i><i>') + '</i>').query('.')
) AS [A]
CROSS APPLY
[X].[nodes]('i') AS [X]([C]);
RETURN;
END
And then use query:
SELECT
[t].*
,[Scope] = CASE WHEN [t2].[Scope] IS NULL THEN NULL ELSE 'X' END
,[Cost] = CASE WHEN [t2].[Cost] IS NULL THEN NULL ELSE 'X' END
,[Schedule] = CASE WHEN [t2].[Schedule] IS NULL THEN NULL ELSE 'X' END
,[EVM] = CASE WHEN [t2].[EVM] IS NULL THEN NULL ELSE 'X' END
,[PA] = CASE WHEN [t2].[PA] IS NULL THEN NULL ELSE 'X' END
FROM
[your table] AS [t]
OUTER APPLY
(
SELECT * FROM (SELECT [str] from [dbo].[str__split]([TypeOfChange], ',')) AS [d]
PIVOT
(MAX([str]) FOR [str] IN ([Scope], [Cost], [Schedule], [EVM], [PA])) AS [piv]
) AS [t2]

SQL - Query to seperate single column and create new columns based on column data

Sorry, if the title is horrible. Have a table T. With a column Name, Num, and Status that either contains a I, O, or S.
Ex:
Name Num Status
Bob 1 I
Bob 2 O
Bob 3 O
John 4 I
John 5 S
Joe 6 O
Want result to look like:
Name Num I O S
Bob 1 x
Bob 2 x
Bob 3 X
John 4 X
John 5 X
Thanks!
Edit: Follow up question.
Name Num I O S
Bob 1 x
Bob 1 x
Bob 2 X
Need result:
Name Num I O S
Bob 1 X X
Bob 2 X
EDIT 2: Actual Query:
SELECT Name, Card_Nmbr,
[Out] = case when d.Status='I' then 'X' else '' end,
[In] = case when d.Status='O' then 'X' else '' end,
[Sales] = case when d.Status='S' then 'X' else '' end
FROM [PCOdb].[dbo].[GC_Header] as h
INNER JOIN GC_Detail as d on h.GC_TransNmbr = d.GC_TransNmbr
INNER JOIN GC_Master as m on d.GCM_Nmbr = m.GCM_Nmbr
INNER JOIN Galaxy1.dbo.GxUsers as u on h.UserID = u.UserID
WHERE GC_TransDate between '11/29/16' and dateadd(day,1, '11/29/16')
Group BY Card_Nmbr, Name
A simple case statement would help here
Select Name
,Num
,[I] = case when [Status]='I' then 'X' else '' end
,[O] = case when [Status]='O' then 'X' else '' end
,[S] = case when [Status]='S' then 'X' else '' end
From YourTable
EDIT to handle multiple rows
Select Name
,Num
,[I] = max(case when [Status]='I' then 'X' else '' end)
,[O] = max(case when [Status]='O' then 'X' else '' end)
,[S] = max(case when [Status]='S' then 'X' else '' end)
From YourTable
Group By Name,Num
Edit 2 - Full Query (Assuming the Joins are doing what you need)
SELECT Name
,Card_Nmbr
,[Out] = max(case when d.[Status]='I' then 'X' else '' end)
,[In] = max(case when d.[Status]='O' then 'X' else '' end)
,[Sales] = max(case when d.[Status]='S' then 'X' else '' end)
FROM [PCOdb].[dbo].[GC_Header] as h
JOIN GC_Detail as d on h.GC_TransNmbr = d.GC_TransNmbr
JOIN GC_Master as m on d.GCM_Nmbr = m.GCM_Nmbr
JOIN Galaxy1.dbo.GxUsers as u on h.UserID = u.UserID
WHERE GC_TransDate between '2016-11-29' and DateAdd(DD,1,'2016-11-29')
Group BY Card_Nmbr, Name
Use Case expression.
Demo:
Create table #temp
(Name varchar (10),
Num int ,
[Status] char(1))
insert into #temp values ('Bob' , '1' , 'I')
insert into #temp values ('Bob' , '2' , 'O')
insert into #temp values ('Bob' , '3' , 'O')
insert into #temp values ('John' , '4' , 'I')
insert into #temp values ('John' , '5' ,'S')
insert into #temp values ('Joe' , '6' , 'O')
select Name,
Num,
[I] = case
when [Status] ='I'
then 'X'
else ''
end
,[O] = case
when [Status] ='O'
then 'X'
else ''
end
,[S] = case when [Status] ='S'
then 'X'
else ''
end
from #temp
drop table #temp
Result:
For SQL Server 2012 and Later you can use IIF (Transact-SQL) function too.
Select Name
,Num
,IIF([Status] = 'I' , 'X', '' ) AS [I]
,IIF([Status] = 'O' , 'X', '' ) AS [O]
,IIF([Status] = 'S' , 'X', '' ) AS [S]
FROM TableName

SQL Server query passing list of parameters containing numeric and character id's

MS SQL 2008
I need help with a query. I was working fine before but, now i am getting arguments that overlap rendering this query useless.
Basically, i am passing a list of parameters in the format
'1_s, 22_o, 1_u, 35_t'...
where first token is numeric id and second it the type of the product
Previously, i separated numeric id's from the product types and it was fine because the ids were far apart and there was no overlap. but, now due to system being replaced and ids were restarted i am getting products from different types with the same id as you can see 1_s and 1_u.
How can i separate them?
This is the list of arguments passed as a string:
34_o,31_s,32_o,20_t,18_u,17_u,33_o,38_o,34_s,36_o,22_t,20_u,19_u,37_o,42_o,37_s,40_o,24_t,22_u,21_u,41_o
The the query is below:
SELECT COUNT(bs.product_id) as num_of_products, jb.join_id, jb.join_name, jb.join_name_fr,
SUM(Round(ISNULL(ebs.ee_premium,0),2) + Round(ISNULL(ebs.employer_premium,0),2)) AS premium,
SUM(Round(ISNULL(ebs.ee_premium,0),2)) AS ee_premium,
SUM(Round(ISNULL(ebs.er_premium,0),2)) AS er_premium,
SUM(Round(ISNULL(ebs.ee_tax_prov,0),2) + Round(ISNULL(ebs.er_tax_prov,0),2)) AS sales_tax,
SUM(Round(ISNULL(ebs.ee_tax_fed,0),2) + Round(ISNULL(ebs.er_tax_fed,0),2)) AS fed_tax,
SUM(Round(ISNULL(ebs.ee_tax_hst,0),2) + Round(ISNULL(ebs.er_tax_hst,0),2)) AS hst_tax,
jb.order_id,
CASE
WHEN bsb.product_type = 't' OR bsb.product_type = 'u' OR bsb.product_type = 'o'
THEN SUM(volume)
ELSE 0
END
AS volume_billed,
CASE
WHEN bsb.product_type = 's'
THEN ebs.product_category
ELSE ''
END
FROM BillStatement ebs
INNER JOIN tblEmpInfo bei ON bei.billstatementvalue_id = ebs.billstatementvalue_id
INNER JOIN tblStatementProduct bsb ON bsb.statementproduct_id = ebs.statementproduct_id
INNER JOIN tblStatement bs ON bs.statement_id = bsb.statement_id
INNER JOIN JoinedPlanPoducts jb ON jb.product_id = bsb.product_id AND jb.product_type = bsb.product_type
WHERE
bsb.product_id IN ((select * from dbo.StringToTable('34,31,32,20,18,17,33,38,34,36,22,20,19,37,42,37,40,24,22,21,41',',')))
AND bsb.product_type IN ('o','s','t','u')
GROUP BY jb.join_id, jb.join_name, jb.join_name_fr, jb.order_id, bsb.product_type, ebs.product_category
I need the list of arguments look something like that:
AND
(
(bsb.product_id IN ((select * from dbo.StringToTable('31,34,37',','))) AND bsb.product_type = 's')
OR
(bsb.product_id IN ((select * from dbo.StringToTable('20,22,24',','))) AND bsb.product_type = 't')
OR
(bsb.product_id IN ((select * from dbo.StringToTable('17,18,19,20,21',','))) AND bsb.product_type = 'u')
OR
(bsb.product_id IN ((select * from dbo.StringToTable('32,33,34,36,37,38,40,41,42',','))) AND bsb.product_type = 'o')
)
UPDATE:
Hi, I need another solution here. I implemented John's parser function and the performance of my query dropped from 3 sec to 30 sec. Considering that the query above in my post is a part of multiple UNION, which is a part of common table expression query, my report runs from before 10 to 15 min and now, the page does not complete at all. The report is an aggregate of large record sets and pulls a lot of aggregate values.
Any input greatly appreciated.
Corrections to arguments should look like below:
AND
(
(bsb.product_id IN (31,34,37) AND bsb.product_type = 's')
OR
(bsb.product_id IN (20,22,24) AND bsb.product_type = 't')
OR
(bsb.product_id IN (17,18,19,20,21) AND bsb.product_type = 'u')
OR
(bsb.product_id IN (32,33,34,36,37,38,40,41,42) AND bsb.product_type = 'o')
)
UPDATE 2
#John
Thank you for the reply. New version is a bit better but its not there.
I updated full query with updated parser and plugged in CTE. Run time has fallen from 30 sec to 20 sec.
I plugged in different versions in WHERE clause to compare with the same set of arguments (quite large list)
This one I have used and, it is fastest, runs 2 sec but, it not reliable because of duplicates in id's and types. For example there can be id=34 and type='s' and type='t'. Therefore, I can not use it.
AND bsb.product_id IN ((select * from dbo.fnStringToTable('1321,1596,1773,1595,1320,799,1775...',','))) AND bsb.product_type IN ('t','s','o','u')
This one with CTE by John (post below) runs 20 sec.
AND bsb.product_id IN (Select benefitID from cteKey)
AND bsb.product_type IN (Select benefitType from cteType)
This one runs 15 sec.
AND (
bab.product_id = 23 AND bab.product_type = 'o'
OR
bab.product_id = 3 AND bab.product_type = 's'
OR
bab.product_id = 1 AND bab.product_type = 't'
OR
bab.product_id = 7 AND bab.product_type = 'u'
OR
bab.product_id = 18 AND bab.product_type = 's'
OR
bab.product_id = 1 AND bab.product_type = 's'
.....)
This one runs 4 sec and I think is ideal under circumstances
AND (
bab.product_id IN (583, 585, 584, 595, 597, 596, 720, 722, 721, 723)
AND bab.product_type = 'o'
OR bab.product_id IN (718, 717, 727, 726, 894, 893, 896, 895, 898, 897, 900, 899) AND bab.product_type = 's'
OR bab.product_id IN (470, 469, 480, 479, 619, 618, 621, 620, 623, 622, 625, 624) AND bab.product_type = 't'
OR bab.product_id IN (388, 392, 446, 447, 450, 451, 453, 454, 455, 456, 457, 458) AND bab.product_type = 'u'
)
Basically, I think I need to separate my arguments by type ('1_s, 22_o, 1_u, 35_t, 28_s, 17_o, 1_t') into a list for each type and build it as in #4.
Updated: Notice the final JOIN and the removal of the WHERE. This
should do what #4 is doing.
The first cte will parse your string (note updated parser)
The second and third cte generate unique keys which are then applied in you where, which may be migrated into the tblStatementProduct JOIN.
Declare #String varchar(max) = '34_o,31_s,32_o,20_t,18_u,17_u,33_o,38_o,34_s,36_o,22_t,20_u,19_u,37_o,42_o,37_s,40_o,24_t,22_u,21_u,41_o'
;with cteParse as (
Select B.*
From (Select * from [dbo].[udf-Str-Parse](#String,',')) A
Cross Apply (
Select Type =max(case when RetSeq=2 then RetVal else '' end)
,KeyValue =max(case when RetSeq=1 then RetVal else '' end)
From (Select * from [dbo].[udf-Str-Parse](A.RetVal,'_')) C
) B )
SELECT COUNT(bs.product_id) as num_of_products
, jb.join_id
, jb.join_name
, jb.join_name_fr
, SUM(Round(ISNULL(ebs.ee_premium,0),2) + Round(ISNULL(ebs.employer_premium,0),2)) AS premium
, SUM(Round(ISNULL(ebs.ee_premium,0),2)) AS ee_premium
, SUM(Round(ISNULL(ebs.er_premium,0),2)) AS er_premium
, SUM(Round(ISNULL(ebs.ee_tax_prov,0),2) + Round(ISNULL(ebs.er_tax_prov,0),2)) AS sales_tax
, SUM(Round(ISNULL(ebs.ee_tax_fed,0),2) + Round(ISNULL(ebs.er_tax_fed,0),2)) AS fed_tax
, SUM(Round(ISNULL(ebs.ee_tax_hst,0),2) + Round(ISNULL(ebs.er_tax_hst,0),2)) AS hst_tax
, jb.order_id
, CASE WHEN bsb.product_type in ('t','u','o') THEN SUM(volume) ELSE 0 END AS volume_billed
, CASE WHEN bsb.product_type = 's' THEN ebs.product_category ELSE '' END
FROM BillStatement ebs
INNER JOIN tblEmpInfo bei ON bei.billstatementvalue_id = ebs.billstatementvalue_id
INNER JOIN tblStatementProduct bsb ON bsb.statementproduct_id = ebs.statementproduct_id
INNER JOIN tblStatement bs ON bs.statement_id = bsb.statement_id
INNER JOIN JoinedPlanPoducts jb ON jb.product_id = bsb.product_id AND jb.product_type = bsb.product_type
INNER JOIN cteParse ps on (bsb.product_id = ps.KeyValue and bsb.product_type = ps.Type
GROUP BY jb.join_id, jb.join_name, jb.join_name_fr, jb.order_id, bsb.product_type, ebs.product_category
Updated UDF which is a Single Statement TVF
ALTER FUNCTION [dbo].[udf-Str-Parse] (#String varchar(max),#Delimiter varchar(10))
Returns Table
As
Return (
Select RetSeq = Row_Number() over (Order By (Select null))
,RetVal = LTrim(RTrim(B.i.value('(./text())[1]', 'varchar(max)')))
From (Select x = Cast('<x>'+ Replace(#String,#Delimiter,'</x><x>')+'</x>' as xml).query('.')) as A
Cross Apply x.nodes('x') AS B(i)
);
--Select * from [dbo].[udf-Str-Parse]('Dog,Cat,House,Car',',')
--Select * from [dbo].[udf-Str-Parse]('John Cappelletti was here',' ')
With the help of a Parser and a cross apply, you could resolve this once and filter on type.
Declare #String varchar(max) = '34_o,31_s,32_o,20_t,18_u,17_u,33_o,38_o,34_s,36_o,22_t,20_u,19_u,37_o,42_o,37_s,40_o,24_t,22_u,21_u,41_o'
Select B.*
From (Select * from [dbo].[udf-Str-Parse](#String,',')) A
Cross Apply (
Select Type =max(case when Key_PS=2 then Key_Value else '' end)
,KeyValue =max(case when Key_PS=1 then Key_Value else '' end)
From (Select * from [dbo].[udf-Str-Parse](A.Key_Value,'_')) C
) B
Returns
Type KeyValue
o 34
s 31
o 32
t 20
u 18
u 17
o 33
o 38
...
u 22
u 21
o 41
My Parser if needed
CREATE FUNCTION [dbo].[udf-Str-Parse] (#String varchar(max),#Delimeter varchar(10))
--Usage: Select * from [dbo].[udf-Str-Parse]('Dog,Cat,House,Car',',')
-- Select * from [dbo].[udf-Str-Parse]('John Cappelletti was here',' ')
Returns #ReturnTable Table (Key_PS int IDENTITY(1,1), Key_Value varchar(max))
As
Begin
Declare #XML xml;Set #XML = Cast('<x>' + Replace(#String,#Delimeter,'</x><x>')+'</x>' as XML)
Insert Into #ReturnTable Select ltrim(rtrim(String.value('.', 'varchar(max)'))) FROM #XML.nodes('x') as T(String)
Return
End