T-SQL Merge from multiple source records - sql-server

I've seen several similar questions but haven't found one that answers my question.
I have a source table with many individual notes for a company
CompanyName, Notes3
Company1, "spoke with someone"
Company2, "Email no longer works"
Company1, "Moved address"
I have a destination table (vchCompanyName is unique here)
vchCompanyName, vchNotes
Company1, "started business in 2005"
Company2, null
I want to end up with
vchCompanyName, vchNotes
Company1, "started business in 2005
spoke with someone
Moved address"
Company2, "Email no longer works"
I have tried this code
WITH CTE
AS (SELECT ROW_NUMBER() OVER (PARTITION BY CompanyName, Notes3 ORDER BY CompanyName) RowNum, *
FROM CompanyContact
)
merge dCompany as target
using CTE as source
on target.vchcompanyname = source.companyname
when matched and len(source.notes3)>0 and source.RowNum = 1
then
update set target.vchnote = vchnote + CHAR(13) + source.Notes3
But get the error
The MERGE statement attempted to UPDATE or DELETE the same row more than once. This happens when a target row matches more than one source row. A MERGE statement cannot UPDATE/DELETE the same row of the target table multiple times. Refine the ON clause to ensure a target row matches at most one source row, or use the GROUP BY clause to group the source rows.
Which is accurate.
I have also tried STRING_AGG but get an undefined UDF error.
How do I change my code to run iteratively?
--EDIT--
I had tried the following update code
WITH CTE
AS (SELECT ROW_NUMBER() OVER (PARTITION BY CompanyName, Notes3 ORDER BY CompanyName) RowNum, *
FROM CompanyContact
)
UPDATE dCompany SET vchNote = vchNote +
(select CHAR(13) + cc.Notes3 from CompanyContact cc
inner JOIN dCompany dc ON dc.vchCompanyName COLLATE database_default = LEFT(cc.CompanyName,50) COLLATE database_default
inner join CTE on dc.vchCompanyName COLLATE database_default = LEFT(CTE.CompanyName,50) COLLATE database_default
WHERE LEN(cc.Notes3)>0
and RowNum = 1
);
But get the error
Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.

#Chris Crawshaw, I will approach this by doing a 'union all' on the source and destination table to pick up all the notes for each company. Then using the STUFF function, it is easy to concatenate all the notes into one cell, while grouping by the induvidual company names. See the mockup below:
DECLARE #Source TABLE (CompanyName VARCHAR(20), Notes3 VARCHAR(50))
INSERT INTO #Source
SELECT 'Company1', 'spoke with someone' UNION ALL
SELECT 'Company2', 'Email no longer works' UNION ALL
SELECT 'Company1', 'Moved address'
DECLARE #Destination TABLE (vchCompanyName VARCHAR(20), vchNotes VARCHAR(500))
INSERT INTO #Destination
SELECT 'Company1', 'started business in 2005' UNION ALL
SELECT 'Company2', NULL
;WITH Temp AS (
SELECT *
FROM
(
SELECT *
FROM
#Destination D
WHERE D.vchNotes is not null
UNION ALL
SELECT *
FROM
#Source S
)h
)
update D
SET D.vchNotes=U.vchNotes
FROM #Destination D
LEFT JOIN(
SELECT t2.vchCompanyName, vchNotes=STUFF((
SELECT ',' + vchNotes
FROM Temp t1 where t1.vchCompanyName=t2.vchCompanyName
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 1, '')
FROM
#Destination t2
GROUP BY
t2.vchCompanyName
)U ON
U.vchCompanyName=D.vchCompanyName
--TEST--
SELECT *
FROM
#Destination

Related

How to present row data in JSON format in SQL Server 2014

I want to present the data which is getting after joined with another table. It is getting multiple records for one particular Id. So I want to display those multiple records in JSON format.
I have the below data.
Declare #Employees Table (EmpId int, EmpName Varchar(100))
INSERT INTO #Employees
VALUES(1,'RAM')
,(2,'RAJ')
,(3,'LAXMAN')
Declare #Subjects Table (EmpId int, Subject Varchar(100))
INSERT INTO #Subjects
VALUES(1,'Maths')
,(1,'Science')
,(1,'Physics')
,(2,'Physics')
,(3,'Maths')
,(3,'Physics')
I have tried with this query.
SELECT E.EmpId
,Subject
FROM #Employees E
LEFT JOIN (
SELECT EmpId
,'{' + STUFF((
SELECT ',"' + NULLIF(Subject, '') + '"'
FROM #Subjects AS CG1
WHERE CG1.EmpId = CG2.EmpId
FOR XML PATH('')
), 1, 1, '') + '}' AS Subject
FROM #Subjects AS CG2
GROUP BY EmpId
) SUB ON SUB.EmpId = E.EmpId
But I want the result like this.
EmpId Subject
-----------------------------------------------------
1 {"1":"Maths","2":"Science","3":"Physics"}
2 {"1":"Physics"}
3 {"1":"Maths","2":"Physics"}
Please let me know if you want any further information is needed.
I would appreciate your help.
Thanks
You were very close, you need to add a ROW_NUMBER to the subquery too. I've also switched to CONCAT for easy implicit conversions:
SELECT E.EmpId,
Subject
FROM #Employees E
LEFT JOIN (SELECT EmpId,
'{' + STUFF((SELECT CONCAT(',"', ROW_NUMBER() OVER (ORDER BY CG1.Subject), '":"', NULLIF(Subject, ''), '"')
FROM #Subjects CG1
WHERE CG1.EmpId = CG2.EmpId
ORDER BY Subject
FOR XML PATH('')),1,1,'') + '}' AS Subject
FROM #Subjects CG2
GROUP BY EmpId) SUB ON SUB.EmpId = E.EmpId;
Note that the order of the subjects in your table isn't preserved, due to that there is no way to preserve it with an ORDER BY (at least not with the data we have). Therefore 'Physics' has a number of 2 instead of 3 for Empid 1

Stored Procedure Syntax with CTE

This is probably trivial but I am just learning about CTE (thanks to help here).
I have a procedure that is used to determine totals.
The first part is the totals are the sum of a position at their level an below. So I needed a way to retrieve records that (1) determined the level of the record (hierarchy) and (2) returned all records at and below. That was asked and answered here.
Now want to take the CTE table from the answer above and use it in the second part of my procedure (get the totals)
CREATE PROCEDURE [dbo].[GetProgramTotals]
#programId nvarchar(10) = null,
#owner int = null,
#totalAmount money OUT,
#usedAmount money OUT,
#remainingAmount money OUT
AS
BEGIN
WITH rCTE AS
(
SELECT
*, 0 AS Level
FROM Forecasting.dbo.Addressbook
WHERE Addressbook = #owner
UNION ALL
SELECT
t.*, r.Level + 1 AS Level
FROM Addressbook t
INNER JOIN rCTE r ON t.ParentAddressbook = r.Addressbook
)
Select #totalAmount = (Select Sum(Amount) from dbo.Budget where
(#programId IS NULL or (ProgramId = #programId)) and (#owner IS NULL or (BudgetOwner in (SELECT Addressbook from rCTE))))
Select #usedAmount = (Select Sum(SubTotal) from dbo.OrderLine where
(#programId IS NULL or (ProgramId = #programId) and (#owner IS NULL) or (Budget in (SELECT Addressbook from rCTE))))
if (#totalAmount is null)
set #totalAmount = 0
if (#usedAmount is null)
set #usedAmount = 0
Set #remainingAmount = (#totalAmount - #usedAmount)
END
The idea of this procedure is the dynamically calculate an individual (or all) programs based an a users position in a hierarchy.
So a regional managers totals would be the sum of all districts and district reps.
UPDATE: I updated this based on squillman (thank you) comment below.
Now I have a different problem. When I execute the proc - I get 'Invalid object name rCTE'.
You can't use SET in the middle of a query like that. Change it to a SELECT and it should remedy your syntax error.
CREATE PROCEDURE [dbo].[GetProgramTotals]
#programId nvarchar(10) = null,
#owner int = null,
#totalAmount money OUT,
#usedAmount money OUT,
#remainingAmount money OUT
AS
BEGIN
WITH rCTE AS(
SELECT *, 0 AS Level FROM Forecasting.dbo.Addressbook WHERE Addressbook = #owner
UNION ALL
SELECT t.*, r.Level + 1 AS Level
FROM Addressbook t
INNER JOIN rCTE r ON t.ParentAddressbook = r.Addressbook)
SELECT #totalAmount = (Select Sum(Amount) from dbo.Budget where
(#programId IS NULL or (ProgramId = #programId)) and (#owner IS NULL or (BudgetOwner in (SELECT Addressbook from rCTE))))
, #usedAmount = (Select Sum(SubTotal) from dbo.OrderLine where
(#programId IS NULL or (ProgramId = #programId) and (#owner IS NULL) or (Budget in (SELECT Addressbook from rCTE))))
if (#totalAmount is null)
set #totalAmount = 0
if (#usedAmount is null)
set #usedAmount = 0
Set #remainingAmount = (#totalAmount - #usedAmount)
END
CTE's can be a bit confusing at first, but they are really quite simple once they make sense. For me it clicked when I began thinking of them as just another temp table syntax (pro-tip: they're not in reality, just conceptually). So basically:
Create one or more "temp tables". These are your CTE expressions, and there can be more than one.
Perform a standard operation using one or more of the CTE expressions in the statement immediately following your CTE(s).
As Martin mentioned in comments below, the CTE(s) are only scoped for the next immediate statement and fall out of scope after that.
So,
;WITH cte1 AS
(
SELECT Col1 FROM Table1
),
cte2 AS
(
SELECT Col1 FROM Table2
)
SELECT Col1 FROM cte1 //In scope here
UNION
SELECT Col1 FROM cte1; //Still in scope since we're still in the first statement
SELECT Col1 FROM cte1; //Fails. cte1 is now out of scope (as is cte2)
In your case you're using the recursive CTE to form a parent/child hierarchy and then setting variables based on the results. Your CTE syntax is pretty close after the edit, you just need the comma to bring things back together into one statement.
//Variable assignment example
;WITH cte1 AS
(
SELECT Col1 FROM Table1
),
cte2 AS
(
SELECT Col1 FROM Table2
)
SELECT #var1 = (SELECT TOP 1 Col1 FROM cte1)
,#var2 = (SELECT TOP 1 Col1 FROM cte2) //You're missing the comma at the start of this line
Change Select #usedAmount=... to , #usedAmount=...

How to select delimited texts separately and completely SQL Server table column

I have a SQL Server table with a column p_author containing semi-colon (;) delimited text value. I used this query to split and select the respective id's from another table but it only splits once whereas I need all the value id's after splitting either p_author contains one value, two values, three values or whatever number of values. Under is the used query for splitting and selecting respective id's from another table.
select aid as [CountedID]
from sub_aminer_author
where name like (select RIGHT(p_author, LEN(p_author) - CHARINDEX(';', p_author))
from sub_aminer_paper
where pid = 4)
Sample data is shown here in this image.
#DarkKnight--This is my output in SqlServer2014
Try this..
DECLARE #X XML
DECLARE #STR VARCHAR(MAX)=''
Select #STR = #STR+';'+P_AUTHOR
From sub_aminer_paper
WHERE PID = 4
ORDER BY PID
select #STR = substring(#STR,2,len(#STR))
SELECT #X = CONVERT(xml,' <root> <s>' + REPLACE(#STR,';','</s> <s>') + '</s> </root> ')
select aid as [CountedID], name
from sub_aminer_author s
inner join (
SELECT row_number() over(order by (select null)) as rn, T.c.value('.','varchar(max)') as value
FROM #X.nodes('/root/s') T(c)) t on t.value = s.name
order by rn
Example fiddle : http://sqlfiddle.com/#!3/34b6c/10
As it has been said in the comments, you really need to remove this bad design.
It will only lead to bigger problems and performance issues. (I know that sometime you have to deal will terrible design for a little while)
In the meantime, if you really need to split your rows, this type of query with a recursive CTE (SQL Fiddle)can be used:
create table sub_aminer_author(pid int, p_author varchar(max), name varchar(max));
go
Insert into sub_aminer_author(pid, p_author, name) values
(1, 'AAAA;BBBBB;CCCCC', 'AAAA'), (2, 'DDDDD;EEEEE;FFFF;GGGGGGGG', 'GGGGGGGG'), (3, 'HHH', 'GGGGGGGG');
go
with split(pid, first, pos) as(
Select pid, cast(1 as bigint)
, Case When CHARINDEX(';', p_author) > 0
Then CHARINDEX(';', p_author)-1 Else len(p_author) End
From sub_aminer_author
Union All
Select d.pid, s.pos+2
, Case When CHARINDEX(';', d.p_author, s.pos+2) > 0 Then CHARINDEX(';', d.p_author, s.pos+2)-1 Else len(p_author) End
From split s
Inner Join sub_aminer_author d on d.pid = s.pid
Where s.pos < len(d.p_author)-1
)
Select d.pid, s.first, s.pos , SUBSTRING(d.p_author, s.first, s.pos - s.first +1)
From split s
Inner Join sub_aminer_author d on d.pid = s.pid
order by d.pid, s.first
You have to understand that it is neither good nor efficient.
It should be ok as long as you only temporary use it to fix your current design issue and move splited data to a better design.

SQL Pivot table without aggregate

I have a number of text files that are in a format similar to what is shown below.
ENTRY,1,000000,Widget 4000,1,,,2,,
FIELD,Type,A
FIELD,Component,Widget 4000
FIELD,Vendor,Acme
ENTRY,2,000000,PRODUCT XYZ,1,,,3,
FIELD,Type,B
FIELD,ItemAssembly,ABCD
FIELD,Component,Product XYZ - 123
FIELD,Description1,Product
FIELD,Description2,XYZ-123
FIELD,Description3,Alternate Part #440
FIELD,Vendor,Contoso
They have been imported into a table with VARCHAR(MAX) as the only field. Each ENTRY is a "new" item, and all the subsequent FIELD rows are properties of that item. The data next to the FIELD is the column name of the property. The data to the right of the property is the data I want to display.
The desired output would be:
ENTRY Type Component Vendor ItemAssembly Description1
1,000000,Widget 4000 A Widget 4000 Acme
2,000000,Product XYZ B Product XYZ-123 Contoso ABCD Product
I've got the column names using the code below (there are several tables that I have UNIONed together to list all the property names).
select #cols =
STUFF (
(select Distinct ', ' + QUOTENAME(ColName) from
(SELECT
SUBSTRING(ltrim(textFileData),CHARINDEX(',', textFileData, 1)+1,CHARINDEX(',', textFileData, CHARINDEX(',', textFileData, 1)+1)- CHARINDEX(',', textFileData, 1)-1) as ColName
FROM [MyDatabase].[dbo].[MyTextFile]
where
(LEFT(textFileData,7) LIKE #c)
UNION
....
) A
FOR XML PATH(''), TYPE).value('.','NVARCHAR(MAX)'),1,1,'')
Is a Pivot table the best way to do this? No aggregation is needed. Is there a better way to accomplish this? I want to list out data next to the FIELD name in a column format.
Thanks!
Here is the solution in SQL fiddle:
http://sqlfiddle.com/#!3/8f0b0/8
Prepare raw data in format (entry, field, value), use dynamic SQL to make pivot on unknown column count.
MAX() for string is enough to simulate "without aggregate" behavior in this case.
create table t(data varchar(max))
insert into t values('ENTRY,1,000000,Widget 4000,1,,,2,,')
insert into t values('FIELD,Type,A')
insert into t values('FIELD,Component,Widget 4000')
insert into t values('FIELD,Vendor,Acme ')
insert into t values('ENTRY,2,000000,PRODUCT XYZ,1,,,3,')
insert into t values('FIELD,Type,B')
insert into t values('FIELD,ItemAssembly,ABCD')
insert into t values('FIELD,Component,Product XYZ - 123')
insert into t values('FIELD,Description1,Product ')
insert into t values('FIELD,Description2,XYZ-123 ')
insert into t values('FIELD,Description3,Alternate Part #440')
insert into t values('FIELD,Vendor,Contoso');
create type preparedtype as table (entry varchar(max), field varchar(max), value varchar(max))
declare #prepared preparedtype
;with identified as
(
select
row_number ( ) over (order by (select 1)) as id,
substring(data, 1, charindex(',', data) - 1) as type,
substring(data, charindex(',', data) + 1, len(data)) as data
from t
)
, tree as
(
select
id,
(select max(id)
from identified
where type = 'ENTRY'
and id <= i.id) as parentid,
type,
data
from identified as i
)
, pivotsrc as
(
select
p.data as entry,
substring(c.data, 1, charindex(',', c.data) - 1) as field,
substring(c.data, charindex(',', c.data) + 1, len(c.data)) as value
from tree as p
inner join tree as c on c.parentid = p.id
where p.id = p.parentid
and c.parentid <> c.id
)
insert into #prepared
select * from pivotsrc
declare #dynamicPivotQuery as nvarchar(max)
declare #columnName as nvarchar(max)
select #columnName = ISNULL(#ColumnName + ',','')
+ QUOTENAME(field)
from (select distinct field from #prepared) AS fields
set #dynamicPivotQuery = N'select * from #prepared
pivot (max(value) for field in (' + #columnName + ')) as result'
exec sp_executesql #DynamicPivotQuery, N'#prepared preparedtype readonly', #prepared
Here your are, this comes back exactly as you need it. I love tricky SQL :-). This is a real ad-hoc singel-statement call.
DECLARE #tbl TABLE(OneCol VARCHAR(MAX));
INSERT INTO #tbl
VALUES('ENTRY,1,000000,Widget 4000,1,,,2,,')
,('FIELD,Type,A')
,('FIELD,Component,Widget 4000')
,('FIELD,Vendor,Acme ')
,('ENTRY,2,000000,PRODUCT XYZ,1,,,3,')
,('FIELD,Type,B')
,('FIELD,ItemAssembly,ABCD')
,('FIELD,Component,Product XYZ - 123')
,('FIELD,Description1,Product ')
,('FIELD,Description2,XYZ-123 ')
,('FIELD,Description3,Alternate Part #440')
,('FIELD,Vendor,Contoso');
WITH OneColumn AS
(
SELECT ROW_NUMBER() OVER(ORDER BY (SELECT 1)) AS inx
,CAST('<root><r>' + REPLACE(OneCol,',','</r><r>') + '</r></root>' AS XML) AS Split
FROM #tbl AS tbl
)
,AsParts AS
(
SELECT inx
,Each.part.value('/root[1]/r[1]','varchar(max)') AS Part1
,Each.part.value('/root[1]/r[2]','varchar(max)') AS Part2
,Each.part.value('/root[1]/r[3]','varchar(max)') AS Part3
,Each.part.value('/root[1]/r[4]','varchar(max)') AS Part4
,Each.part.value('/root[1]/r[5]','varchar(max)') AS Part5
FROM OneColumn
CROSS APPLY Split.nodes('/root') AS Each(part)
)
,TheEntries AS
(
SELECT DISTINCT *
FROM AsParts
WHERE Part1='ENTRY'
)
SELECT TheEntries.Part2 + ',' + TheEntries.Part3 + ',' + TheEntries.Part4 AS [ENTRY]
,MyFields.AsXML.value('(fields[1]/field[Part2="Type"])[1]/Part3[1]','varchar(max)') AS [Type]
,MyFields.AsXML.value('(fields[1]/field[Part2="Component"])[1]/Part3[1]','varchar(max)') AS Component
,MyFields.AsXML.value('(fields[1]/field[Part2="Vendor"])[1]/Part3[1]','varchar(max)') AS Vendor
,MyFields.AsXML.value('(fields[1]/field[Part2="ItemAssembly"])[1]/Part3[1]','varchar(max)') AS ItemAssembly
,MyFields.AsXML.value('(fields[1]/field[Part2="Description1"])[1]/Part3[1]','varchar(max)') AS Description1
FROM TheEntries
CROSS APPLY
(
SELECT *
FROM AsParts AS ap
WHERE ap.Part1='FIELD' AND ap.inx>TheEntries.inx
AND ap.inx < ISNULL((SELECT TOP 1 nextEntry.inx FROM TheEntries AS nextEntry WHERE nextEntry.inx>TheEntries.inx ORDER BY nextEntry.inx DESC),10000000)
ORDER BY ap.inx
FOR XML PATH('field'), ROOT('fields'),TYPE
) AS MyFields(AsXML)

Dynamic SQL Pivot Query with Union All

I have a static pivot query that tracks historical pricing (see below); it is union all of one table of current data, one table of historical data, and one related table.
I would like to convert it to a dynamic SQL pivot query so that I don't manually have to update the column heading dates all of the time, but I am having problems doing so. The data comes out of an accounting system (Microsoft Dynamics) running on SQL Server, and due to system limitations, I am unable to use ansi nulls/ paddings/ warnings and also unable to use quoted identifiers. Is there another way to create a dynamic sql pivot query?
Here is my current query. I want to replace the month-end dates with dynamic sql. I have view access to the data only.
SELECT ACTDESCR AS "ACCT NAME", concat(right(actnumbr_2,2), actnumbr_3) as PLU, [3/31/2015], [2/28/2015], [1/31/2015], [12/31/2015], [11/30/2014], [10/31/2014], [9/30/2014], [8/31/2014], [7/31/2014], [6/30/2014], [5/31/2014], [4/30/2014], [3/31/2014], [2/28/2014], [1/31/2014]
FROM
(SELECT A.ACTDESCR, EOMONTH(DATEFROMPARTS(B.YEAR1,B.PERIODID,1),0) AS DATE1, A.actnumbr_2, a.actnumbr_3, B.PERDBLNC, A.ACTNUMBR_1
FROM TEST.dbo.table1 AS A
LEFT OUTER JOIN TEST.dbo.TABLE2 AS b
ON (a.ACTINDX = b.ACTINDX)
UNION ALL
SELECT A.ACTDESCR, EOMONTH(DATEFROMPARTS(C.YEAR1,C.PERIODID,1),0) AS DATE1, A.actnumbr_2, a.actnumbr_3, C.PERDBLNC, A.ACTNUMBR_1
FROM TEST.dbo.TABLE1 AS A
LEFT OUTER JOIN TEST.dbo.TABLE3 AS C
ON (a.ACTINDX = C.ACTINDX)
) AS ST
PIVOT
(
SUM(PERDBLNC)
FOR DATE1 IN ([3/31/2015], [2/28/2015], [1/31/2015], [12/31/2015], [11/30/2014], [10/31/2014], [9/30/2014], [8/31/2014], [7/31/2014], [6/30/2014], [5/31/2014], [4/30/2014], [3/31/2014], [2/28/2014], [1/31/2014])
) AS PVT
WHERE ACTNUMBR_1 = ?
You can use T-SQL with dynamic SQL for this:
--VARIABLE TO HOLD DATES--
DECLARE #DATES NVARCHAR(500)
--VARIABLE TO HOLD CODE--
DECLARE #SQL NVARCHAR(MAX)
--TEMP TABLE TO FIND DISTINCT DATES--
CREATE #DATES (COLUMNVALS NVARCHAR(10))
--INSERT DISTINCT DATES INTO TEMP TABLE--
INSERT INTO #DATES
SELECT DISTINCT DATE1 FROM (
SELECT EOMONTH(DATEFROMPARTS(YEAR1,PERIODID,1),0) AS DATE1
FROM TEST.DBO.TABLE2
UNION ALL
SELECT EOMONTH(DATEFROMPARTS(YEAR1,PERIODID,1),0) AS DATE1
FROM TEST.DBO.TABLE3)
--CONCAT DATES INTO SELECT LIST--
SET #DATES = COALESCE(#DATES+', ','') + '[' + DATE1 + ']' FROM #DATES
--CREATE THE SELECT STATEMENT--
SELECT #SQL = '
;WITH ST AS (
SELECT A.ACTDESCR, EOMONTH(DATEFROMPARTS(B.YEAR1,B.PERIODID,1),0) AS DATE1, A.ACTNUMBR_2, A.ACTNUMBR_3, B.PERDBLNC, A.ACTNUMBR_1
FROM TEST.DBO.TABLE1 AS A
LEFT OUTER JOIN TEST.DBO.TABLE2 AS B
ON A.ACTINDX = B.ACTINDX
UNION ALL
SELECT A.ACTDESCR, EOMONTH(DATEFROMPARTS(C.YEAR1,C.PERIODID,1),0) AS DATE1, A.ACTNUMBR_2, A.ACTNUMBR_3, C.PERDBLNC, A.ACTNUMBR_1
FROM TEST.DBO.TABLE1 AS A
LEFT OUTER JOIN TEST.DBO.TABLE3 AS C
ON A.ACTINDX = C.ACTINDX)
SELECT ACTDESCR AS "ACCT NAME", CONCAT(RIGHT(ACTNUMBR_2,2), ACTNUMBR_3) AS PLU, '+#DATES+'
FROM ST
PIVOT
(
SUM(PERDBLNC)
FOR DATE1 IN ('+#DATES+')
) AS PVT
WHERE ACTNUMBR_1 = ?'
--PRINT IT TO SEE WHAT IT'S DONE--
PRINT #SQL
--EXECUTE IT--
EXEC (#SQL)

Resources