Get index of row within a group? - tsql

I have two tables:
Unit:
UnitId int PK
Title varchar
UnitOption:
UnitOptionId int PK
UnitId int FK
Title varchar
Quote:
QuoteId int PK
UnitOptionId int FK
Title varchar
I want to create a scalar UDF that takes a QuoteId param and returns a varchar that contains the following description (pseudu):
Quote.Title + '-' + Unit.Title + '-' + Unit.UnitId +
/* Here is where my question is:
If there are more than 1 UnitOption under this Unit, then
return '-' + the UnitOption number under this Unit
(i.e.) if under this Unit, there are 3 UnitOption with IDs 13, 17, 55
under the unit, and the current Quote.UnitOptionId is the 17 one,
it should return 2.
Which means I want to retrieve an ID of this row in the group.
Else
return ''
*/

If you're using SQL 2005 or later and I've interpreted your question correctly, you should be able to adapt the following into your function.
WITH [UnitExt] AS
(
SELECT
[Unit].[UnitId],
[Unit].[Title],
COUNT(*) AS [Count]
FROM [Unit]
INNER JOIN [UnitOption] ON [UnitOption].[UnitId] = [Unit].[UnitId]
GROUP BY
[Unit].[UnitId],
[Unit].[Title]
)
SELECT
[Quote].[Title] + '-' + [UnitExt].[Title] + '-' + [UnitExt].[UnitId] +
CASE
WHEN [UnitExt].[Count] > 1 THEN '-' +
CAST([UnitOption].[UnitOptionId] AS varchar(max))
ELSE ''
END
FROM [Quote]
INNER JOIN [UnitOption] ON [UnitOption].[UnitOptionId] =
[Quote].[UnitOptionId]
INNER JOIN [UnitExt] ON [UnitExt].[UnitId] = [UnitOption].[UnitId]
WHERE [Quote].[QuoteId] = #QuoteId

Something like this should do it.
SELECT DISTINCT Quote.Title +
' - ' + Unit.Title +
' - ' + Unit.UnitId +
CASE
WHEN COUNT(*) OVER(PARTITION BY Quote.Id) > 0
THEN
' - ' + CAST(ROW_NUMBER() OVER (PARTITION BY Quote.Id ORDER BY Quote.UnitOptionId) AS varchar)
ELSE
''
END
FROM Quote
JOIN UnitOption ON UnitOption.Id = Quote.UnitOptionId
JOIN Unit ON Unit.Id = UnitOption.UnitId
WHERE Quote.Id = #QuoteId

CREATE FUNCTION ufnGetDescription
(#QuoteID INT)
RETURNS VARCHAR(MAX)
AS
BEGIN
DECLARE #RetVal VARCHAR(MAX);
WITH CurRow
AS (SELECT quote.title + '- ' + unit.title AS start,
u.unitid,
quoteid,
uo.unitoptionid
FROM quote
INNER JOIN unitoption uo
ON quote.unitoptionid = uo.unitoptionid
INNER JOIN unit
ON uo.unitid = unit.unitid
WHERE quote.quoteid = #QuoteID),
AllUnits
AS (SELECT u.unitid,
uo.unitoptionid,
Row_number()
OVER(PARTITION BY u.unitid ORDER BY uo.unitoptionid) AS NUMBER,
Count(* )
OVER(PARTITION BY u.unitid ) AS cntUnits
FROM unit
INNER JOIN unionoption uo
ON unit.unitid = uo.unitid
WHERE u.unitid IN (SELECT unitid
FROM CurRow))
SELECT #RetVal = CASE
WHEN a.cntUnits = 1 THEN ''
ELSE r.start + '-' + Cast(NUMBER AS VARCHAR(max))
END
FROM AllUnits a
INNER JOIN CurRow r
ON a.unitoptionid = r.unitoptionid
RETURN #RetVal
END

Related

T-SQL how to assign a variable inside another variable assignment

I've inherited a stored proc and I need to add and assign a new variable. The piece of the code that's relevant is:
DECLARE #tableRows VARCHAR(MAX) = '';
SET #tableRows
= N'<tr>
<bgcolor="#6081A0" style="FONT-FAMILY:arial,san-serif;FONT-WEIGHT:normal;color:#6081A0"> :: Resource Scheduler</tr>'
+ N'<tr>
Date: ' + CAST(CONVERT(NVARCHAR, DATENAME(WEEKDAY, #rpt_start_date)) AS VARCHAR(100)) + ' '
+ CAST(CONVERT(NVARCHAR, CAST(#rpt_start_date AS DATE), 100) AS VARCHAR(100)) + '</tr>'
+ '<table border="1" width="100%">'
+ '<tr bgcolor="#DC5E3F" style="FONT-FAMILY:arial,san-serif;FONT-WEIGHT:bold;color:white">'
+ '<td style="text-align:center;vertical-align:middle">START TIME</td>'
+ '<td style="text-align:center;vertical-align:middle">END TIME</td>'
+ '<td style="text-align:center;vertical-align:middle">ROOM</td>'
+ '<td>MEETING TITLE</td>'
+ '<td style="text-align:center;vertical-align:middle">ATTENDEES</td>'
+ '<td>INVITEE' + CHAR(39) + 'S NAME</td><td>HOSTS NAMES</td>'
+ '<td>FOOD SERVICES REQUESTS</td>'
+ '<td>TECHNOLOGY REQUESTS</td>'
+ '<td>OFFICE SERVICES REQUESTS</td></tr>';
SELECT #tableRows
= #tableRows + '<tr ' + 'bgcolor=' +
+ IIF(ROW_NUMBER() OVER (ORDER BY s.[sched_id] DESC) % 2 = 0, '"lightgrey', '"white') + '">'
+ '<td style="text-align:center;vertical-align:middle">' + CAST(CONVERT(NVARCHAR, CAST(srd.[mtg_start_date_local] AS TIME), 100) AS VARCHAR(100)) + '</td>'
+ '<td style="text-align:center;vertical-align:middle">' + CAST(CONVERT(NVARCHAR, CAST(srd.[mtg_end_date_local] AS TIME), 100) AS VARCHAR(100)) + '</td>'
+ '<td style="text-align:center;vertical-align:middle">' + CAST(r.[res_hdr] AS VARCHAR(100)) + '</td>'
+ '<td>' + CAST(s.[sched_desc] AS VARCHAR(100)) + '</td>'
+ '<td style="text-align:center;vertical-align:middle">' + CAST(s.[num_attendees] AS VARCHAR(100)) + '</td>'
+ '<td>' + CAST(ru.[user_name] AS VARCHAR(100)) + '</td>'
+ '<td>' + CAST(hu.[user_name] AS VARCHAR(100)) + '</td>'
+ '<td>' + CAST(dbo.ufn_rsConcatCustomTabServices(#rs_customtab_food,s.[sched_id]) AS VARCHAR(4000)) + '</td>'
+ '<td>' + CAST(dbo.ufn_rsConcatCustomTabServices(#rs_customtab_tech,s.[sched_id]) AS VARCHAR(4000)) + '</td>'
+ '<td>' + CAST(dbo.ufn_rsConcatCustomTabServices(#rs_customtab_os,s.[sched_id]) AS VARCHAR(4000)) + '</td></tr>'
FROM
tbl_sched s WITH (NOLOCK)
INNER JOIN
tbl_sched_res_date srd WITH (NOLOCK)
ON s.[sched_id] = srd.[sched_id]
INNER JOIN
tbl_sched_request sr WITH (NOLOCK)
ON s.[sched_id] = sr.[sched_id]
INNER JOIN
tbl_user ru WITH (NOLOCK)
ON sr.[req_for_user_id] = ru.[user_id]
INNER JOIN
tbl_user hu WITH (NOLOCK)
ON s.create_by = hu.[user_id]
INNER JOIN
tbl_res r WITH (NOLOCK)
ON srd.[res_id] = r.[res_id]
INNER JOIN
tbl_grp g WITH (NOLOCK)
ON r.[grp_id] = g.[grp_id]
INNER JOIN
tbl_loc l WITH (NOLOCK)
ON g.[loc_id] = l.[loc_id]
INNER JOIN
tbl_region rg WITH (NOLOCK)
ON l.[region_id] = rg.[region_id]
LEFT OUTER JOIN -- changed from inner join
tbl_sched_udf_val suv_f WITH (NOLOCK)
ON suv_f.[sched_id] = s.[sched_id]
AND suv_f.[udf_id] =
(
SELECT
u.[udf_id]
FROM
tbl_udf u WITH (NOLOCK)
WHERE
u.[udf_desc] LIKE #rs_customtab_food
)
AND suv_f.[string_value] IS NOT NULL
AND suv_f.[string_value] = 'Yes'
LEFT OUTER JOIN -- changed from inner join
tbl_sched_udf_val suv_t WITH (NOLOCK)
ON suv_t.[sched_id] = s.[sched_id]
AND suv_t.[udf_id] =
(
SELECT
u.[udf_id]
FROM
tbl_udf u WITH (NOLOCK)
WHERE
u.[udf_desc] LIKE #rs_customtab_tech
)
AND suv_t.[string_value] IS NOT NULL
AND suv_t.[string_value] = 'Yes'
LEFT OUTER JOIN -- changed from inner join
tbl_sched_udf_val suv_o WITH (NOLOCK)
ON suv_o.[sched_id] = s.[sched_id]
AND suv_o.[udf_id] =
(
SELECT
u.[udf_id]
FROM
tbl_udf u WITH (NOLOCK)
WHERE
u.[udf_desc] LIKE #rs_customtab_os
)
AND suv_o.[string_value] IS NOT NULL
AND suv_o.[string_value] = 'Yes'
LEFT OUTER JOIN
tbl_sched_res_setup srs WITH (NOLOCK)
ON (
s.[sched_id] = srs.[sched_id]
AND srd.[res_id] = srs.[res_id]
)
LEFT OUTER JOIN
tbl_setup su WITH (NOLOCK)
ON (srs.[setup_id] = su.[setup_id])
WHERE
l.[loc_id] = 13-- 1177 Sixth Ave ( ONLY )
AND s.[deleted_flag] = 0
AND r.[obsolete_flag] = 0
AND g.[obsolete_flag] = 0
AND l.[obsolete_flag] = 0
AND rg.[obsolete_flag] = 0
AND srd.[busy_start_date_local] >= CONVERT(NVARCHAR(20), #rpt_start_date, 112)
AND srd.[busy_start_date_local] < CONVERT(NVARCHAR(20), #rpt_end_date, 112)
ORDER BY
srd.[mtg_start_date_local],
r.[res_hdr];
SELECT #tableRows = #tableRows + '</table>';
As you can see, it's a complicated query. #tableRows is used later on to create the body of an email. Now, I need to get s.sched_desc (see line 7 of SELECT statement) and assign it to a second variable, so that I can use it in the Subject line of the same email. I've tried adding
+ (SELECT #sched_desc = SELECT [sched_desc])
to the bottom of the SELECT statement but it's no good (incorrect syntax near parenthesis). I've also tried
+ '<td>' + (SELECT #sched_desc = CAST(s.[sched_desc] AS VARCHAR(100))) + '</td>'
but again it's expecting another parenthesis. I know I can do this by turning this whole thing into a string and then executing it with sp_executesql (see this example) but I'd prefer to avoid dynamic sql if possible. On the other hand, I really don't want to execute this query twice. Is there another way to get around this?
Your stated task would be more easily accomplished and supported by employing a templating language and some basic string interpolation.
It is not possible to set a variable value within the process of setting another variable's value, but you can do so within the same SELECT.
In your query, add a comma after the closing quote and then set your #sched_desc variable:
SELECT #tableRows = #tableRows + '<tr ' + 'bgcolor=' ... </td></tr>',
#sched_desc = [sched_desc]
FROM tbl_sched s WITH (NOLOCK)
INNER JOIN tbl_sched_res_date srd WITH (NOLOCK)
ON s.[sched_id] = srd.[sched_id]
...
The second variable assignment has access to the same data as the original query, but it will need to be included in whatever selecting process is used to retrieve the value of #tableRows.
As an additional note, I will strongly advise you to identify alternatives to using NOLOCK - here are some links to get you started on that path:
https://www.brentozar.com/archive/2021/11/nolock-is-bad-and-you-probably-shouldnt-use-it/
https://www.brentozar.com/archive/2018/10/using-nolock-heres-how-youll-get-the-wrong-query-results/
https://www.brentozar.com/archive/2016/12/nolock-ever-right-choice/
https://www.brentozar.com/archive/2021/01/but-surely-nolock-is-okay-if-no-ones-changing-data-right/
Paneerakbari is correct that you can assign (and build up) more than one variable in the select. Here is a simplified example that may make things clearer.
DECLARE #TableRows VARCHAR(MAX) = '<table>'
DECLARE #Subject VARCHAR(MAX) = '' -- Only the last value is retained here
SELECT
#TableRows = #TableRows + '<tr><td>' + A.Info + '</td></tr>',
#Subject = A.Title
FROM (
VALUES
(1, 'This', 'This stuff'),
(2, 'That', 'That stuff'),
(3, 'More', 'More stuff')
) A(ID, Title, Info)
ORDER BY A.ID
SET #TableRows = #TableRows + '</table>'
SELECT #Subject, #TableRows
Result:
#Subject = 'More'
#TableRows = '<table><tr><td>This stuff</td></tr><tr><td>That stuff</td></tr><tr><td>More stuff</td></tr></table>'
For readability and maintainability, I often find it useful to move complex intermediate calculations into a CROSS APPLY block, the results of which can then be referenced in the final select.
DECLARE #TableRows VARCHAR(MAX) = '<table>'
DECLARE #Subject VARCHAR(MAX) = '' -- Only the last value is retained here
SELECT
#TableRows = #TableRows + R.ComplexRowConstruction,
#Subject = A.Title
FROM (
VALUES
(1, 'This', 'This stuff'),
(2, 'That', 'That stuff'),
(3, 'More', 'More stuff')
) A(ID, Title, Info)
CROSS APPLY (
SELECT ComplexRowConstruction =
'<tr>'
+ '<td>' + A.Info + '</td>'
+ '</tr>'
) R
ORDER BY A.ID
SET #TableRows = #TableRows + '</table>'
SELECT #Subject, #TableRows

How to fix Incorrect syntax near '=' error in stored procedure that uses dynamic SQL

I attempted to add some additional columns to an existing stored procedure. This entailed not only adding the columns but also creating a LEFT JOIN subquery to gather the additional columns that is commented on " Addition of Sales and Warranties totals". Now, when I execute this code within my stored procedure, I'm getting an error in the SQL command.
I've tried opening a new query window and trying to recreate the query in the proper format to execute it, but I get the following errors: Msg 102, Level 15, State 1, Line 60
Incorrect syntax near ' + case when isnull(#TaxHeaders,') = ' then '.
Msg 102, Level 15, State 1, Line 117
Incorrect syntax near ' + case when isnull(#TaxHeaders,') = ' then '.
I've also tried changing the location of my LEFT JOIN query (SWT,GT) above the T and T1 LEFT JOIN that includes the pivot.
CREATE Procedure [GP].[spInvoiceReprintsSummary]
#CompanyKey varchar(2)=5,
#ParentCustomerNum varchar(255)='BCAA01', --'AAANYCITY', --'AAANPENN01', --'CAAQUEBE01', --'BCAA01', --'CAAQUEBE01',
#StartDateKey varchar(8)=20130306,
#EndDateKey varchar(8)=20130315,
#TaxHeaders varchar(255)='HST,GST,PST,QST' --'GST, QST'
As
Begin
Declare #SQL as varchar(max)
Set #SQL = '
Select S.CompanyKey, S.TaxScheduleID, S.CustomerKey, S.ParentCustomerNum, S.StationID, S.CustomerName, S.DocumentTypeKey, S.DocumentNum, Case When Left(S.DocumentNum, 2)=''ST'' Then 0 ELSE 1 End As EligibleDiscount,S.ExtendedPrice,S.PurchaseOrderNum, DocumentDate, S.TaxAmount, SWT.SalesTotal, SWT.WarrantiesTotal, S.TerritoryId ' + case when isnull(#TaxHeaders,'') = '' then '' else ',' + #TaxHeaders end + ' From
(
--Get distinct documents
Select --Top 100
SD.CompanyKey, SD.TaxScheduleID, CS.CustomerKey, CS.ParentCustomerNum, CS.StationID, CS.CustomerName, SD.DocumentTypeKey, SD.DocumentNum,SD.PurchaseOrderNum, convert(datetime,convert(varchar, DateKey, 112)) As DocumentDate,sum(SD.TaxAmount) as TaxAmount, sum(SD.ExtendedPrice) As ExtendedPrice, CS.TerritoryId From GP.SalesDetail SD
Inner Join GP.Customers CS
on SD.CustomerKey = CS.CustomerKey
Where CS.ParentCustomerNum= ''' + #ParentCustomerNum + ''' And SD.DateKey Between ' + #StartDateKey + ' and ' + #EndDateKey + ' And SD.CompanyKey = ' + #CompanyKey + ' And SD.PostStatus = 1 And SD.VoidStatus = 0
Group by SD.CompanyKey, SD.TaxScheduleID, CS.CustomerKey, CS.ParentCustomerNum, CS.StationID, CS.CustomerName, SD.DocumentTypeKey, SD.DocumentNum,SD.PurchaseOrderNum, convert(datetime,convert(varchar, DateKey, 112)), CS.TerritoryId
--Order By SD.PurchaseOrderNum, SD.DocumentTypeKey
) S
---Addition of sales and warranties totals
LEFT JOIN(
SELECT CASE WHEN GroupName = ''SALES'' then sum(QuantitySold) else 0 end as SalesTotal,CASE WHEN GroupName = ''WARRANTIES'' then sum(QuantitySold) else 0 end as WarrantiesTotal, DocumentNum, CompanyKey FROM
(SELECT
SD.QuantitySold , DocumentNum , SD.CompanyKey
,CASE WHEN I.userDefItemClass1 = ''BATTERY/RETURN'' AND SD.QuantitySold >= 0 THEN ''SALES''
WHEN I.userDefItemClass1 = ''BATTERY/RETURN'' AND SD.QuantitySold < 0 THEN ''RETURNS''
WHEN I.ItemNum = ''RESTOCKING FEE'' AND sd.ExtendedPrice >= 0 THEN ''RETURNS''
WHEN I.ItemNum = ''RESTOCKING FEE'' AND sd.ExtendedPrice < 0 THEN ''SALES''
WHEN I.userDefItemClass1 = ''WARRANTY'' THEN ''WARRANTIES''
WHEN I.userDefItemClass1 = ''NRF'' THEN ''RECYCLING FEES''
WHEN I.userDefItemClass1 = ''CORES'' THEN ''SPENT BATTERIES''
WHEN I.ItemNum IN (''PU2'',''PU4.3'') AND sd.ExtendedPrice > 0 THEN ''RETURNS''
WHEN I.ItemNum IN (''PU2'',''PU4.3'') AND sd.ExtendedPrice < 0 THEN ''SALES''
ELSE ''OTHER'' END AS GroupName
FROM GP.SalesDetail AS SD
INNER JOIN GP.Items AS I ON SD.ItemKey = I.ItemKey
Inner Join GP.Customers CS on SD.CustomerKey = CS.CustomerKey
WHERE
CS.ParentCustomerNum= '' + #ParentCustomerNum + '' And SD.DateKey Between ' + #StartDateKey + ' and ' + #EndDateKey + ' And SD.CompanyKey = ' + #CompanyKey + ' And SD.PostStatus = 1 And SD.VoidStatus = 0
) GN
GROUP BY DocumentNum, GroupName, CompanyKey
) SWT
ON S.Companykey = SWT.CompanyKey And S.DocumentNum = SWT.DocumentNum
Left join (
--Pivot the Tax Types
Select Companykey, DocumentTypeKey, DocumentNum ' + case when isnull(#TaxHeaders,'') = '' then '' else ',' + #TaxHeaders end + ' From (
SELECT SD.CompanyKey,TD.DocumentTypeKey, TD.DocumentNum, TS.TaxDetailLabel, SUM(TD.TaxAmount) AS TaxAmount
FROM GP.TaxSchedules AS TS INNER JOIN
(SELECT SD.CompanyKey, SD.TaxScheduleId, SD.DocumentTypeKey, SD.DocumentNum
FROM GP.SalesDetail SD
Inner Join GP.Customers CS
on SD.CustomerKey = CS.CustomerKey
Where CS.ParentCustomerNum= ''' + #ParentCustomerNum + ''' And SD.DateKey Between ' + #StartDateKey + ' and ' + #EndDateKey + ' And SD.CompanyKey = ' + #CompanyKey + ' And SD.PostStatus = 1 And SD.VoidStatus = 0
GROUP BY SD.CompanyKey, SD.TaxScheduleId, SD.DocumentTypeKey, SD.DocumentNum) AS SD
ON TS.CompanyKey = SD.CompanyKey AND TS.TaxScheduleId = SD.TaxScheduleId
INNER JOIN GP.TaxDetails AS TD ON TD.DocumentNum = SD.DocumentNum AND TD.DocumentTypeKey = SD.DocumentTypeKey AND
TD.LineItemSequenceNum = 0 AND TD.TaxDetailID = TS.TaxDetailId AND TD.CompanyKey = TS.CompanyKey
GROUP BY SD.CompanyKey,TD.DocumentTypeKey,TD.DocumentNum, TS.TaxDetailLabel
) T
Pivot (sum(TaxAmount) For TaxDetailLabel In (' + case when isnull(#TaxHeaders,'') = '' then 'Tax' else #TaxHeaders end + ')) as PVT
) T1
on S.Companykey = T1.CompanyKey And S.DocumentTypeKey = T1.DocumentTypeKey And S.DocumentNum = T1.DocumentNum'
--print #SQL
Exec (#SQL)
End
I expect an output of the original result set including the new columns for SalesTotal and WarrantiesTotal
Replace
CASE
WHEN isnull(#taxheaders,'') = ''
then ''
ELSE ',' + #taxheaders
END
with
CASE
WHEN #taxheaders IS NULL
THEN ''
ELSE ',' + #taxheaders
This should fix the error. Thanks..

Get characters before underscore and separated by comma from a string in SQL Server 2008

I tried this query
DECLARE #AdvancedSearchSelectedDropdownName TABLE (
SelectedIds VARCHAR(2048),
AdvanceSearchOptionTypeId INT
)
INSERT INTO #AdvancedSearchSelectedDropdownName
VALUES ('4_0,5_1,6_2,7_3', 23),
('62_3', 21), ('2_4', 23)
DECLARE #selectedIds VARCHAR(MAX) = '';
SELECT #selectedIds +=
CASE WHEN SelectedIds IS NULL
THEN #selectedIds + ISNULL(SelectedIds + ',', '')
WHEN SelectedIds IS NOT NULL
THEN SUBSTRING(SelectedIds, 0, CHARINDEX('_', SelectedIds, 0)) + ','
END
FROM #AdvancedSearchSelectedDropdownName WHERE advanceSearchOptionTypeId = 23
SELECT #selectedIds
Current output: 4,2
Required output: 4,5,6,7,2
We may have n number of comma separated values in the SelectedIds column.
You might go this route:
WITH Casted AS
(
SELECT *
,CAST('<x><y>' + REPLACE(REPLACE(SelectedIds,'_','</y><y>'),',','</y></x><x><y>') + '</y></x>' AS XML) SplittedToXml
FROM #AdvancedSearchSelectedDropdownName
)
SELECT *
FROM Casted;
This will return your data in this form:
<x>
<y>4</y>
<y>0</y>
</x>
<x>
<y>5</y>
<y>1</y>
</x>
<x>
<y>6</y>
<y>2</y>
</x>
<x>
<y>7</y>
<y>3</y>
</x>
Now we can grab all the x and just the first y:
WITH Casted AS
(
SELECT *
,CAST('<x><y>' + REPLACE(REPLACE(SelectedIds,'_','</y><y>'),',','</y></x><x><y>') + '</y></x>' AS XML) SplittedToXml
FROM #AdvancedSearchSelectedDropdownName
)
SELECT Casted.AdvanceSearchOptionTypeId AS TypeId
,x.value('y[1]/text()[1]','int') AS IdValue
FROM Casted
CROSS APPLY SplittedToXml.nodes('/x') A(x);
The result:
TypeId IdValue
23 4
23 5
23 6
23 7
21 62
23 2
Hint: Do not store comma delimited values!
It is a very bad idea to store your data in this format. You can use a generic format like my XML to store this or a structure of related side tables. But such construction tend to turn out as a real pain in the neck...
After a little re-think. Perhaps something a little more straightforward.
Now, if you have a limited number of _N
Example
;with cte as (
Select *
,RN = Row_Number() over(Order by (Select NULL))
From #AdvancedSearchSelectedDropdownName A
)
Select AdvanceSearchOptionTypeId
,IDs = replace(
replace(
replace(
replace(
replace(
stuff((Select ',' +SelectedIds From cte Where AdvanceSearchOptionTypeId=A.AdvanceSearchOptionTypeId Order by RN For XML Path ('')),1,1,'')
,'_0','')
,'_1','')
,'_2','')
,'_3','')
,'_4','')
From cte A
Group By AdvanceSearchOptionTypeId
Returns
AdvanceSearchOptionTypeId IDs
21 62
23 4,5,6,7,2
If interested in a helper function.
Tired of extracting strings (left, right, charindex, patindex, ...) I modified s split/parse function to accept TWO non-like delimiters. In this case a , and _.
Example
;with cte as (
Select A.AdvanceSearchOptionTypeId
,B.*
,RN = Row_Number() over(Order by (Select NULL))
From #AdvancedSearchSelectedDropdownName A
Cross Apply [dbo].[tvf-Str-Extract](','+A.SelectedIds,',','_') B
)
Select AdvanceSearchOptionTypeId
,IDs = stuff((Select ',' +RetVal From cte Where AdvanceSearchOptionTypeId=A.AdvanceSearchOptionTypeId Order by RN,RetVal For XML Path ('')),1,1,'')
From cte A
Group By AdvanceSearchOptionTypeId
Returns
AdvanceSearchOptionTypeId IDs
21 62
23 4,5,6,7,2
The TVF if Interested
CREATE FUNCTION [dbo].[tvf-Str-Extract] (#String varchar(max),#Delimiter1 varchar(100),#Delimiter2 varchar(100))
Returns Table
As
Return (
with cte1(N) As (Select 1 From (Values(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) N(N)),
cte2(N) As (Select Top (IsNull(DataLength(#String),0)) Row_Number() over (Order By (Select NULL)) From (Select N=1 From cte1 N1,cte1 N2,cte1 N3,cte1 N4,cte1 N5,cte1 N6) A ),
cte3(N) As (Select 1 Union All Select t.N+DataLength(#Delimiter1) From cte2 t Where Substring(#String,t.N,DataLength(#Delimiter1)) = #Delimiter1),
cte4(N,L) As (Select S.N,IsNull(NullIf(CharIndex(#Delimiter1,#String,s.N),0)-S.N,8000) From cte3 S)
Select RetSeq = Row_Number() over (Order By N)
,RetPos = N
,RetVal = left(RetVal,charindex(#Delimiter2,RetVal)-1)
From (
Select *,RetVal = Substring(#String, N, L)
From cte4
) A
Where charindex(#Delimiter2,RetVal)>1
)
/*
Max Length of String 1MM characters
Declare #String varchar(max) = 'Dear [[FirstName]] [[LastName]], ...'
Select * From [dbo].[tvf-Str-Extract] (#String,'[[',']]')
*/
Disclaimer.As per first Normal form, you should not store multiple values in a single cell. I would suggest you to avoid storing this way.
Still the approach would be: Create a UDF function which separates comma separated list into a table valued variable. Below code I have not tested. but, it gives idea on how to approach this problem.
Refer to CSV to table approaches
Declare #selectedIds varchar(max) = '';
SET #selectedIds = SELECT STUFF
(SELECT ','+ (SUBSTRING(c.value, 0, CHARINDEX('_', c.value, 0))
FROM #AdvancedSearchSelectedDropdownName AS tv
CROSS APPLY dbo.udfForCSVToList(SelectedIds) AS c
WHERE advanceSearchOptionTypeId = 23
FOR XML PATH('')),1,2,'');
SELECT #selectedIds

T_SQL The multi part identifier could not be bound error

I have a query which works fine, but I am trying to create a dynamic pivot out of it to get a better end result table.
I found this on SO but I cant relate it to my issue.
The multi-part identifier could not be bound
My working code is this:
DECLARE #RangeDate as date
set #RangeDate = (select distinct cd.weDate from CM_DATA cd where cd.year = 2015 and cd.week = 45)
set #RangeDate = DATEADD(WW, -7, #RangeDate)
DECLARE #SQL as VARCHAR(MAX)
DECLARE #Columns AS VARCHAR(MAX)
SELECT #Columns =
COALESCE(#Columns + ', ','') + QUOTENAME(YearWeek)
FROM
(
SELECT DISTINCT YearWeek
FROM CM_DATA
where weDate >= #RangeDate
) AS B
SET #SQL = '
WITH PivotData AS
(
select cd.Country
, cd.Chain
, cd.YearWeek
, left(sm.Planogram, 2) as planogram
, cd.StoreNo
, cd.UID
, cd.ShortCode
, lp.Family
, lp.ColourShort
, pr.type
, cd.Volume
, ul.WOSOR
from vw_V2_UsrVarLst ul
left join CM_DATA cd on cd.Country = ul.CountryCode and cd.Chain = ul.Chain
left join V2_StoreMaster sm on sm.CountryCode = ul.CountryCode and sm.Chain = ul.Chain and sm.StoreNo = cd.StoreNo and sm.StoreNm = cd.StoreNm and cd.YearWeek between sm.YYYYWW and sm.YYYYWWEND
left join tblProducts pr ON pr.[COUNTRY CODE] = ul.CountryCode and pr.SKU = cd.UID
left join V2_LanguagePack LP ON LP.ShortCode = cd.ShortCode AND lp.Lang = ul.UsrLang
where cd.Country = ul.CountryCode and cd.Chain = ul.Chain and planogram is not null and left(cd.UID, 10) in (select lv.UID from V2_live lv where lv.CountryCode = ul.CountryCode and lv.Chain = ul.Chain and cd.YearWeek between lv.YYYYWW and lv.YYYYWWEND) and cd.weDate >= ' + #RangeDate + ' and sm.Planogram != ''Z''
)
select cd.Country
, cd.Chain
, left(sm.Planogram, 2) as planogram
, cd.StoreNo
, cd.UID
, cd.ShortCode
, lp.Family
, lp.ColourShort
, pr.type
, cd.Volume
, ' + #Columns + '
, ul.WOSOR
FROM PivotData
PIVOT
(
SUM(Volume)
FOR YearWeek
IN(' + #Columns + ')
) AS PivotResult'
EXEC (#SQL)
Can anyone spot what up here
KR
Martin
Try SELECT #SQL instead of your EXEC.
You probably must set the output to Text and use the query options (right click into the query window) to set the max length of text output to a higher value (maximum is 8192).
Than you can paste the result of your dynamic SQL into a new query window and execute this there. You should get a speaking error message and you should even jump to the right place with a double click...
Good luck!

T-SQL Nested Subquery

I want to place this working code within a SQL Statement, OR do I need to perform a UDF.
The result set is a one line concatenation, and I want it to be place in every one of the overall result set lines.
----
MAIN QUERY
SELECT
H.CONNECTION_ID,
H.SEQUENTIAL_NO,
H.INVOICE_NUMBER,
H.INVOICE_DATE,
H.LAST_INVOICE_NUMBER,
H.LAST_INVOICE_DATE,
CAST(CASE
WHEN H.COLLECT_DEPOSIT = 1 THEN '-'
ELSE CAST(H.PAYMENT_DUE_DATE AS NVARCHAR(20))
END AS SMALLDATETIME) AS PAYMENT_DUE,
H.JOB_NUMBER,
H.CUST_JOB_NUMBER,
HDR.SALES_PERSON,
H.INSIDE_SALES_PERSON,
H.IS_LAST_INVOICE,
CASE
WHEN H.COLLECT_DEPOSIT = 1 THEN 'CASH'
ELSE H.PAYMENT_TERMS_DESCRIPTION
END AS PAYMENT_TERMS,
H.PRINTED,
H.NOTES,
CUR.ID,
CUR.CODE,
CASE CUR.CODE
WHEN 'USD' THEN '001-106624-211'
WHEN 'EUR' THEN '001-106624-101'
WHEN 'GBP' THEN '001-106624-100'
ELSE '001-106624-001'
END AS BANK_ACCT,
CUR.EXCHANGE_RATE,
H.BILL_CONTACT,
H.CUST_ACCOUNT,
H.CUST_NAME,
H.CUST_ADDR1,
H.CUST_ADDR2,
H.CUST_CITY,
H.CUST_STATE,
H.CUST_ZIP,
H.CONTACT_PHONE_NUMBER,
H.CONTACT_PHONE_NUMBER2,
H.ORDERED_BY_CONTACT,
H.SHIP_TO_NAME,
H.SHIP_TO_ADDR1,
H.SHIP_TO_ADDR2,
H.SHIP_TO_CITY,
H.SHIP_TO_STATE,
H.SHIP_TO_ZIP,
H.SITE_PHONE_NUMBER,
H.SITE_PHONE_NUMBER2,
H.OFFICE_NAME,
H.OFFICE_ADDR1,
H.OFFICE_ADDR2,
H.OFFICE_CITY,
H.OFFICE_STATE,
H.OFFICE_ZIP,
H.OFFICE_PHONE_NUMBER,
H.OFFICE_FAX_NUMBER,
H.DELIVERY_TICKET_NUMBER,
H.PO_NUMBER,
H.DUMMY_INVOICE_TEXT,
(SELECT MESSAGE FROM REPORT_MESSAGES WHERE CODE = 'INVOICE') ADVERT_MESSAGE,
(SELECT MAX(DISCOUNT_PERCENTAGE) FROM PRTINVITEM I2 WHERE I2.CONNECTION_ID = H.CONNECTION_ID AND I2.INVOICE_NUMBER = H.INVOICE_NUMBER) AS MAX_DISCOUNT,
I.ITEM,
I.DESCRIPTION,
I.QUANTITY,
I.UNIT_OF_MEASURE,
I.MINIMUM_CHARGE,
I.WEEKLY_CHARGE,
I.MONTHLY_CHARGE,
I.START_OF_BILLING_PERIOD,
I.END_OF_BILLING_PERIOD,
I.DAYS_USED,
I.WEEKS_USED,
I.DISCOUNT_PERCENTAGE,
I.TAX_CODE_FOR_ITEM,
I.INVENTORY_TYPE,
I.BILLING_LOGIC_TYPE,
I.ACTUAL_WEEKLY_CHARGE_USED,
I.DAYS_IN_ACTUAL_WEEKLY_CHARGE,
II.CHARGEABLE_DAYS,
II.CHARGEABLE_WEEKS,
II.CHARGEABLE_MONTHS,
II.FREE_DAYS_THIS_INVOICE,
CNV.TOTAL_NET_VALUE,
CNV.TOTAL_TAX_VALUE,
CNV.TOTAL_GROSS_VALUE,
CNV.TOTAL_GROSS_VALUE_NS,
CNV.NET_LINE_VALUE,
CMP.EMAIL_ADDRESS
FROM (PRTINVHDR H INNER JOIN PRTINVITEM I ON H.CONNECTION_ID = I.CONNECTION_ID AND H.INVOICE_NUMBER = I.INVOICE_NUMBER)
INNER JOIN INVOICEHDR HDR ON I.INVOICE_NUMBER = HDR.INVNO
INNER JOIN CUSTOMERS CST ON H.CUST_ACCOUNT = CST.CUSTNUM
INNER JOIN JOB JOB ON H.JOB_NUMBER = JOB.JOBNUM
INNER JOIN CURRENCY CUR ON HDR.CURRENCY_ID = CUR.ID
INNER JOIN VWCURRENCYCONVERSION CNV ON I.CONNECTION_ID = CNV.CONNECTION_ID AND I.INVC_UCOUNTER = CNV.INVC_UCOUNTER
INNER JOIN COMPANY CMP ON H.OFFICE_CODE = CMP.OFFICE
INNER JOIN INVOICEITEM II ON I.INVOICE_NUMBER = II.INVNO AND I.INVC_UCOUNTER = II.INVC_UCOUNTER
ORDER BY
H.SEQUENTIAL_NO,
I.PRINT_SEQUENCE
ASC
----
COALESCE QUERY
DECLARE
#DTICKET NVARCHAR(20),
#PUMPCATEGORYNAME NVARCHAR(3999)
SET #DTICKET = ''
SET #PUMPCATEGORYNAME = NULL
(SELECT
#DTICKET = DTICKET,
#PUMPCATEGORYNAME = COALESCE(#PUMPCATEGORYNAME + ', ', '' ) + PUMPCATEGORYNAME
FROM (SELECT
BHDR.DTICKET,
SCD.PUMPCATEGORYNAME
FROM PRTTICKHDR PHDR
INNER JOIN BIDHDR BHDR ON PHDR.DELIV_TICKET_NUMBER = BHDR.DTICKET
INNER JOIN PRTTICKITEM PITM ON PHDR.CONNECTION_ID = PITM.CONNECTION_ID AND PHDR.DELIV_TICKET_NUMBER = PITM.DELIV_TICKET_NUMBER
LEFT JOIN SUBCATEGORYDESCRIPTION SCD ON PITM.ITEM = SCD.PUMPCATEGORY
WHERE SCD.PUMPCATEGORYNAME IS NOT NULL)
SUBCATEGORYDESCRIPTION)
SELECT #DTICKET, #PUMPCATEGORYNAME
Not really sure what you are asking for but you can doing something along the lines of
Select col1 + ', ' + col2 + ', ' + col3 etc....