SQL Union Or Join Horizantally - sql-server

I am trying to get the below queries into one row on a query. Below is just an example, I have about 10 counts to combine into one row
select ISNULL(COUNT(*),0) as ENGLAND from Service_User s
where s.commissioner_id ='1'
select ISNULL(COUNT(*),0) as WALES from Service_User s
where s.commissioner_id ='2'
select ISNULL(COUNT(*),0) as GERMANY from Service_User s
where s.commissioner_id ='3'
I have tried to UNION them but they appear vertically and I want them horizontally.
I would like it to appear like below

Try this. Use Sub-select
SELECT (SELECT Isnull(Count(*), 0)
FROM Service_User s
WHERE s.commissioner_id = '1') AS ENGLAND,
(SELECT Isnull(Count(*), 0)
FROM Service_User s
WHERE s.commissioner_id = '2') AS WALES,
(SELECT Isnull(Count(*), 0)
FROM Service_User s
WHERE s.commissioner_id = '3') AS GERMANY

If you are using Sql Server 2012 or above then it can be shorter .
Try this,
;With CTE As
(
select commissioner_id, ROW_NUMBER()Over(Partition By commissioner_id order by commissioner_id) RowNum from Service_User s
s.commissioner_id in(1,2,3)
)
,CTE1 as
(
Select commissioner_id,MAX(RowNum) from CTE
group By commissioner_id
)
select * from CTE
--pivot this result set

If I knew for fact that my commissioner_id's were not doing to change and I could load the values to pivot on into the query I would go with option 1.
SELECT * FROM (select COUNT(*) As Count,(select case commissioner_id when '01' then 'England' when '02' then 'Wales' when '03' then 'Germany' else 'Other') as [Location] from Service_User group by [Location]) as s PIVOT (SUM(count) FOR [Location] IN ("England","Wales","Germany","Other")) AS PivotOut
Second Option I would create a stored procedure that dynamically loaded the options for commissioner_id and then pivoted. This way as the commissioner_ids are added there is no manual intervention to return the required results.
Create PROCEDURE [dbo].[DynamicSP]
AS
BEGIN
declare #sql as varchar(max)
declare #dynamic varchar(max)
select #dynamic=COALESCE(#dynamic +',','')+commissioner_id
FROM
(select distinct commissioner_id from Service_User) as CommIds order by commissioner_id
set #SQL = '(select COUNT(*) As count,commissioner_id as [Location] from Service_User group by [Location]) as s PIVOT (SUM(count) FOR [Location] IN (' + #dynamic + ')) AS PivotOut'
exec(#sql)
END

Related

A simple pivot but can't get my head around it - please assist..:-)

I try to do a simple pivot in MS SSMS, but can't figure it out.
This is my data set:
Date CallerANI Skills CallerDNIS
2019-05-27 27315391449 loc-SPD-CSR-OverFlow 47515070001
2019-05-27 27315391449 cc-Loc-Voice Transfer
and statement:
SELECT [Date],
CallerANI,
[47515001101],
[Transfer]
FROM (SELECT [Date], Skills, CallerANI, CallerDNIS FROM #TempDB) AS p
PIVOT (MAX(Skills)
FOR CallerDNIS IN ([47515001101], [Transfer])) AS pvt;
I want to pivot so that the result looks like this:
Date CallerANI [47515070001] [Transfer]
2019-05-27 273135391449 loc-SPD-CSR-OverFlow cc-loc-Voice
Personally, I prefer to use a Cross Tab over the inbuilt PIVOT function. I find it far easier to use:
SELECT [Date],
CallerANI,
MAX(CASE WHEN V.CallerDNIS = '47515070001' THEN Skills END) AS [47515070001],
MAX(CASE WHEN V.CallerDNIS = 'Transfer' THEN Skills END) AS [Transfer]
FROM (VALUES (CONVERT(date,'20190527'),27315391449,'loc-SPD-CSR-OverFlow','47515070001'),
(CONVERT(date,'20190527'),27315391449,'cc-Loc-Voice','Transfer')) V([Date],CallerANI,Skills,CallerDNIS)
GROUP BY [Date],
CallerANI;
The below code helps you to dynamically Pivot N number of rows
DECLARE #DynamicCols VARCHAR(MAX);
CREATE TABLE #temp ([Date] DATE, [CallerANI] VARCHAR(MAX), [Skills] VARCHAR(MAX), [CallerDNIS] VARCHAR(MAX))
INSERT INTO #temp
VALUES ('2019-05-27','27315391449','loc-SPD-CSR-OverFlow','47515070001'),
('2019-05-27','27315391449','cc-Loc-Voice','Transfer'),
('2019-05-27','27315391449','cc-Loc-Voice-abc','SoMe')
SELECT * FROM #temp
SELECT #DynamicCols = STUFF([Cols],1,1,'') FROM (
SELECT [Cols] = (SELECT ',' + QUOTENAME([CallerDNIS]) FROM #temp A
FOR XML PATH('') ) ) A;
EXEC ('
SELECT [Date], [CallerANI], ' + #DynamicCols+'
FROM #temp
PIVOT
(
MAX([Skills])
FOR [CallerDNIS] in (' + #DynamicCols+')
) PIV');

Create a SQL Stored Procedure with Dynamic Column Names

I have the following stored procedure:
ALTER PROCEDURE [dbo].[sp_RequestCategoryCount]
#StDate1 DATE,
#EnDate1 DATE,
#StDate2 DATE,
#EnDate2 DATE
AS
BEGIN
SELECT DISTINCT RQ.request_category
INTO #ReqCat
FROM
(SELECT DISTINCT request_category
FROM [VerInt_OneViewServiceReq]
UNION ALL
SELECT DISTINCT request_category
FROM [VerInt_OneViewServiceReq2]) RQ
SELECT
'1' as Iteration,
request_category,
SUM(1) AS Record_Count
INTO
#Iter1
FROM
[VerInt_OneViewServiceReq]
WHERE
request_created_dt BETWEEN #StDate1 AND #EnDate1
GROUP BY
request_category
-- UNION ALL
SELECT
'2' as Iteration,
request_category,
SUM(1) as Record_Count
INTO
#Iter2
FROM
[VerInt_OneViewServiceReq2]
WHERE
request_created_dt BETWEEN #StDate2 AND #EnDate2
GROUP BY
request_category
-- ORDER BY Iteration, request_category ASC
SELECT
RC.request_category,
IT1.Record_Count as RecordCountDateRange1,
IT2.Record_Count as RecordCountDateRange2
FROM
#ReqCat RC
LEFT JOIN
#Iter1 IT1 ON IT1.request_category = RC.request_category
LEFT JOIN
#Iter2 IT2 ON IT2.request_category = RC.request_category
DROP TABLE #ReqCat
DROP TABLE #Iter1
DROP TABLE #Iter2
END
All it does is basically compare 2 timespans of data in 2 tables by lining them up side-by-side, and works fine.
What I'd like to do is replace this from the last SELECT statement:
SELECT
RC.request_category,
IT1.Record_Count as RecordCountDateRange1,
IT2.Record_Count as RecordCountDateRange2
FROM
#ReqCat RC
with something that would "air code" like this:
SELECT
RC.request_category,
IT1.Record_Count AS "#StDate1_to_#EnDate1",
IT2.Record_Count AS "#StDate2_to_#EnDate2"
FROM
#ReqCat RC
so that the field names would indicate the dates used in the comparison.
Is this possible to do without re-writing the whole procedure, and, if so, how would I do it?
Yes, this is possible by using dynamic SQL. I cannot test it but more or less it should work as you specified. It will show on screen (messages area) the sentence being run and you can adjust the SELECT #SQL = ... as per your convenience until you find your correct statement:
ALTER procedure [dbo].[sp_RequestCategoryCount]
#StDate1 date,
#EnDate1 date,
#StDate2 date,
#EnDate2 date
AS
BEGIN
DECLARE #SQL AS NVARCHAR(MAX);
SELECT distinct RQ.request_category
into #ReqCat
FROM ( Select distinct request_category from [VerInt_OneViewServiceReq]
UNION ALL
Select distinct request_category from [VerInt_OneViewServiceReq2]
) RQ
Select
'1' as Iteration,
request_category,
Sum(1) as Record_Count
INTO #Iter1
from [VerInt_OneViewServiceReq]
where request_created_dt between #StDate1 and #EnDate1
group by request_category
--UNION ALL
Select
'2' as Iteration,
request_category,
Sum(1) as Record_Count
INTO #Iter2
from [VerInt_OneViewServiceReq2]
where request_created_dt between #StDate2 and #EnDate2
group by request_category
--order by Iteration, request_category ASC
SELECT #SQL = '
Select RC.request_category,
IT1.Record_Count as ['+CONVERT(VARCHAR(10), #StDate1)+'_to_'+CONVERT(VARCHAR(10), #EnDate1)+'],
IT2.Record_Count as ['+CONVERT(VARCHAR(10), #StDate2)+'_to_'+CONVERT(VARCHAR(10), #EnDate2)+']
from #ReqCat RC
LEFT JOIN #Iter1 IT1
ON IT1.request_category = RC.request_category
LEFT JOIN #Iter2 IT2
ON IT2.request_category = RC.request_category'
-- Debug purposes
PRINT #SQL;
EXEC sp_ExecuteSQL #SQL;
Drop Table #ReqCat
Drop Table #Iter1
Drop Table #Iter2
END

T-SQL Merge from multiple source records

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

T-SQL: Function that returns multiple queries from a loop

I am trying to create a function that receives as a parameter a start date and a date end of a period and results in a list totaled with the top 5 products sold for each month of the period.
For example:
CREATE FUNCTION top5Sales(#CurrentDate DATETIME, #EndDate DATETIME)
RETURNS TABLE
RETURN
(
WHILE(#CurrentDate < #EndDate)
BEGIN
SELECT TOP 5
AdventureWorks.Sales.SalesOrderDetail.ProductID,
AdventureWorks.Production.Product.Name,
MONTH(AdventureWorks.Sales.SalesOrderHeader.OrderDate) as 'Month',
YEAR(AdventureWorks.Sales.SalesOrderHeader.OrderDate) as 'Year',
SUM(AdventureWorks.Sales.SalesOrderDetail.OrderQty) as 'Total Quantity Sold',
AVG(AdventureWorks.Sales.SalesOrderDetail.UnitPrice) as 'Average Unit Price',
SUM(AdventureWorks.Sales.SalesOrderDetail.UnitPriceDiscount) as 'Total Discount',
SUM(AdventureWorks.Sales.SalesOrderDetail.LineTotal) as 'Total Value Sold'
FROM
AdventureWorks.Sales.SalesOrderDetail
INNER JOIN
AdventureWorks.Sales.SalesOrderHeader
ON
AdventureWorks.Sales.SalesOrderHeader.SalesOrderID = AdventureWorks.Sales.SalesOrderDetail.SalesOrderID
INNER JOIN
AdventureWorks.Production.Product
ON
AdventureWorks.Production.Product.ProductID = AdventureWorks.Sales.SalesOrderDetail.ProductID
WHERE
MONTH(AdventureWorks.Sales.SalesOrderHeader.OrderDate) = month(#CurrentDate)
and
YEAR(AdventureWorks.Sales.SalesOrderHeader.OrderDate) = year(#CurrentDate)
GROUP BY
AdventureWorks.Production.Product.Name,
AdventureWorks.Sales.SalesOrderDetail.ProductID,
MONTH(AdventureWorks.Sales.SalesOrderHeader.OrderDate),
YEAR(AdventureWorks.Sales.SalesOrderHeader.OrderDate)
ORDER BY
[Total Quantity Sold] DESC
SET
#CurrentDate = DATEADD(MONTH, 1, #CurrentDate)
END
)
In fact, the above code is wrong. It serves only to exemplify the problem and give the path to some possible solution.
You do not have to follow that line of thinking. If there is another more interesting solution to this problem, feel free to expose it.
You can use row_number and top 5 with ties and use single query to return this results as below: Can you check this?
CREATE FUNCTION top5Sales(#CurrentDate DATETIME, #EndDate DATETIME)
RETURNS TABLE
RETURN
(
SELECT Top 5 with ties * from (
SELECT
AdventureWorks.Sales.SalesOrderDetail.ProductID,
AdventureWorks.Production.Product.Name,
MONTH(AdventureWorks.Sales.SalesOrderHeader.OrderDate) as 'Month',
YEAR(AdventureWorks.Sales.SalesOrderHeader.OrderDate) as 'Year',
SUM(AdventureWorks.Sales.SalesOrderDetail.OrderQty) as 'Total Quantity Sold',
AVG(AdventureWorks.Sales.SalesOrderDetail.UnitPrice) as 'Average Unit Price',
SUM(AdventureWorks.Sales.SalesOrderDetail.UnitPriceDiscount) as 'Total Discount',
SUM(AdventureWorks.Sales.SalesOrderDetail.LineTotal) as 'Total Value Sold'
FROM
AdventureWorks.Sales.SalesOrderDetail
INNER JOIN
AdventureWorks.Sales.SalesOrderHeader
ON
AdventureWorks.Sales.SalesOrderHeader.SalesOrderID = AdventureWorks.Sales.SalesOrderDetail.SalesOrderID
INNER JOIN
AdventureWorks.Production.Product
ON
AdventureWorks.Production.Product.ProductID = AdventureWorks.Sales.SalesOrderDetail.ProductID
WHERE
AdventureWorks.Sales.SalesOrderHeader.OrderDate > #CurrentDate
AND AdventureWorks.Sales.SalesOrderHeader.OrderDate <= #EndDate
GROUP BY
AdventureWorks.Production.Product.Name,
AdventureWorks.Sales.SalesOrderDetail.ProductID,
MONTH(AdventureWorks.Sales.SalesOrderHeader.OrderDate),
YEAR(AdventureWorks.Sales.SalesOrderHeader.OrderDate)
-- ORDER BY
-- [Total Quantity Sold] DESC
) a
Order by Row_Number() over(Partition by [ProductId], [Name], [Year], [Month] order by [Total Quantity Sold] Desc
)
I checked the AdventureWorks database and I didn't see a Date table. For a basic overview, you can checkout this video - https://www.brentozar.com/training/t-sql-level/3-number-date-tables-10m/
The following logic wouldn't be in an inline-table function, but it's a fast and simple way of SELECTing the data you're looking for.
DECLARE #sql NVARCHAR(Max),
#CurrentDate DATETIME = '2005-06-01 00:00:00.000',
#EndDate DATETIME = '2008-08-31 00:00:00.000';
SELECT #sql = COALESCE( #sql + CHAR(13) + 'UNION' + CHAR(13), '') +
' SELECT TOP 5 ' + CONVERT(NVARCHAR(8), [Year]) + ' AS [Year], '
+ CONVERT(NVARCHAR(8), [Month]) + ' AS [Month],
sod.ProductId,
SUM(sod.OrderQty) AS Sales
FROM Sales.SalesOrderDetail sod
JOIN Sales.SalesOrderHeader soh
ON sod.SalesOrderId = soh.SalesOrderId
AND YEAR(soh.OrderDate) = ' + CONVERT(NVARCHAR(8), [Year]) + '
AND MONTH(soh.OrderDate) = ' + CONVERT(NVARCHAR(8), [Month]) + '
GROUP BY sod.ProductId'
FROM dbo.[Date]
WHERE [Date] BETWEEN #CurrentDate AND #EndDate
EXEC sp_executesql #sql
If you execute this T-SQL you'll find it's very fast and scalable relative to other methods of getting the same data.

SQL Server: combining multiple rows into one row

I have a SQL query like this;
SELECT *
FROM Jira.customfieldvalue
WHERE CUSTOMFIELD = 12534
AND ISSUE = 19602
And that's the results;
What I want is; showing in one row (cell) combined all STRINGVALUE's and they are separated with a comma. Like this;
SELECT --some process with STRINGVALUE--
FROM Jira.customfieldvalue
WHERE CUSTOMFIELD = 12534
AND ISSUE = 19602
Araç Listesi (C2, K1 vb.Belgeler; yoksa Ruhsat Fotokopileri), Min. 5
araç plakası için İnternet Sorgusu, Son 3 Yıla Ait Onaylı Yıl Sonu
Bilanço + Gelir Tablosu, Son Yıl (Yıl Sonuna ait) Detay Mizanı, İçinde
Bulunduğumuz Yıla ait Ara Dönem Geçici Vergi Beyannamesi, Bayi Yorum
E-Maili, Proforma Fatura
How can I do that?
There are several methods.
If you want just the consolidated string value returned, this is a good quick and easy approach
DECLARE #combinedString VARCHAR(MAX)
SELECT #combinedString = COALESCE(#combinedString + ', ', '') + stringvalue
FROM jira.customfieldValue
WHERE customfield = 12534
AND ISSUE = 19602
SELECT #combinedString as StringValue
Which will return your combined string.
You can also try one of the XML methods e.g.
SELECT DISTINCT Issue, Customfield, StringValues
FROM Jira.customfieldvalue v1
CROSS APPLY ( SELECT StringValues + ','
FROM jira.customfieldvalue v2
WHERE v2.Customfield = v1.Customfield
AND v2.Issue = v1.issue
ORDER BY ID
FOR XML PATH('') ) D ( StringValues )
WHERE customfield = 12534
AND ISSUE = 19602
You can achieve this is to combine For XML Path and STUFF as follows:
SELECT (STUFF((
SELECT ', ' + StringValue
FROM Jira.customfieldvalue
WHERE CUSTOMFIELD = 12534
AND ISSUE = 19602
FOR XML PATH('')
), 1, 2, '')
) AS StringValue
This is an old question, but as of the release of Microsoft SQL Server 2017 you can now use the STRING_AGG() function which is much like the GROUP_CONCAT function in MySQL.
STRING_AGG (Transact-SQL) Documentation
Example
USE AdventureWorks2016
GO
SELECT STRING_AGG (CONVERT(NVARCHAR(max),FirstName), ',') AS csv
FROM Person.Person;
Returns
Syed,Catherine,Kim,Kim,Kim,Hazem
There's a convenient method for this in MySql called GROUP_CONCAT. An equivalent for SQL Server doesn't exist, but you can write your own using the SQLCLR. Luckily someone already did that for you.
Your query then turns into this (which btw is a much nicer syntax):
SELECT CUSTOMFIELD, ISSUE, dbo.GROUP_CONCAT(STRINGVALUE)
FROM Jira.customfieldvalue
WHERE CUSTOMFIELD = 12534 AND ISSUE = 19602
GROUP BY CUSTOMFIELD, ISSUE
But please note that this method is good for at the most 100 rows within a group. Beyond that, you'll have major performance problems. SQLCLR aggregates have to serialize any intermediate results and that quickly piles up to quite a lot of work. Keep this in mind!
Interestingly the FOR XML doesn't suffer from the same problem but instead uses that horrendous syntax.
I believe for databases which support listagg function, you can do:
select id, issue, customfield, parentkey, listagg(stingvalue, ',') within group (order by id)
from jira.customfieldvalue
where customfield = 12534 and issue = 19602
group by id, issue, customfield, parentkey
Using MySQL inbuilt function group_concat() will be a good choice for getting the desired result. The syntax will be -
SELECT group_concat(STRINGVALUE)
FROM Jira.customfieldvalue
WHERE CUSTOMFIELD = 12534
AND ISSUE = 19602
Before you execute the above command make sure you increase the size of group_concat_max_len else the the whole output may not fit in that cell.
To set the value of group_concat_max_len, execute the below command-
SET group_concat_max_len = 50000;
You can change the value 50000 accordingly, you increase it to a higher value as required.
CREATE VIEW [dbo].[ret_vwSalariedForReport]
AS
WITH temp1 AS (SELECT
salaried.*,
operationalUnits.Title as OperationalUnitTitle
FROM
ret_vwSalaried salaried LEFT JOIN
prs_operationalUnitFeatures operationalUnitFeatures on salaried.[Guid] = operationalUnitFeatures.[FeatureGuid] LEFT JOIN
prs_operationalUnits operationalUnits ON operationalUnits.id = operationalUnitFeatures.OperationalUnitID
),
temp2 AS (SELECT
t2.*,
STUFF ((SELECT ' - ' + t1.OperationalUnitTitle
FROM
temp1 t1
WHERE t1.[ID] = t2.[ID]
For XML PATH('')), 2, 2, '') OperationalUnitTitles from temp1 t2)
SELECT
[Guid],
ID,
Title,
PersonnelNo,
FirstName,
LastName,
FullName,
Active,
SSN,
DeathDate,
SalariedType,
OperationalUnitTitles
FROM
temp2
GROUP BY
[Guid],
ID,
Title,
PersonnelNo,
FirstName,
LastName,
FullName,
Active,
SSN,
DeathDate,
SalariedType,
OperationalUnitTitles
declare #maxColumnCount int=0;
declare #Query varchar(max)='';
declare #DynamicColumnName nvarchar(MAX)='';
-- table type variable that store all values of column row no
DECLARE #TotalRows TABLE( row_count int)
INSERT INTO #TotalRows (row_count)
SELECT (ROW_NUMBER() OVER(PARTITION BY InvoiceNo order by InvoiceNo Desc)) as row_no FROM tblExportPartProforma
-- Get the MAX value from #TotalRows table
set #maxColumnCount= (select max(row_count) from #TotalRows)
-- loop to create Dynamic max/case and store it into local variable
DECLARE #cnt INT = 1;
WHILE #cnt <= #maxColumnCount
BEGIN
set #DynamicColumnName= #DynamicColumnName + ', Max(case when row_no= '+cast(#cnt as varchar)+' then InvoiceType end )as InvoiceType'+cast(#cnt as varchar)+''
set #DynamicColumnName= #DynamicColumnName + ', Max(case when row_no= '+cast(#cnt as varchar)+' then BankRefno end )as BankRefno'+cast(#cnt as varchar)+''
set #DynamicColumnName= #DynamicColumnName + ', Max(case when row_no= '+cast(#cnt as varchar)+' then AmountReceived end )as AmountReceived'+cast(#cnt as varchar)+''
set #DynamicColumnName= #DynamicColumnName + ', Max(case when row_no= '+cast(#cnt as varchar)+' then AmountReceivedDate end )as AmountReceivedDate'+cast(#cnt as varchar)+''
SET #cnt = #cnt + 1;
END;
-- Create dynamic CTE and store it into local variable #query
set #Query='
with CTE_tbl as
(
SELECT InvoiceNo,InvoiceType,BankRefno,AmountReceived,AmountReceivedDate,
ROW_NUMBER() OVER(PARTITION BY InvoiceNo order by InvoiceNo Desc) as row_no
FROM tblExportPartProforma
)
select
InvoiceNo
'+#DynamicColumnName+'
FROM CTE_tbl
group By InvoiceNo'
-- Execute the Query
execute (#Query)

Resources