Dynamically Join Enum Table with other Table - sql

I have the following table. These are not the real tables but the concept is here.
Table1
----------------------------------
FieldID|EnumeratedValue|TextValue
----------------------------------
Col1 |1 |Hey
----------------------------------
Col1 |2 |Test
----------------------------------
Col1 |3 |George
----------------------------------
Col2 |1 |Random
----------------------------------
Col2 |2 |Wesley
----------------------------------
Col3 |1 |Tompson
----------------------------------
Col3 |2 |Oooo
----------------------------------
Table2
----------------------------------
Col1 |Col2 |Col3
----------------------------------
1 |2 |1
----------------------------------
2 |1 |1
----------------------------------
3 |1 |2
----------------------------------
The desired result would be a view
----------------------------------
Col1 |Col2 |Col3
----------------------------------
Hey |Wesley |Tompson
----------------------------------
Test |Random |Tompson
----------------------------------
George |Random |Oooo
----------------------------------
So you could write something like
SELECT col1.TextValue,col2.TextValue,col3.TextValue
FROM Table2 t2,
(SELECT * FROM Table1 WHERE FieldID = 'Col1') col1,
(SELECT * FROM Table1 WHERE FieldID = 'Col2') col2,
(SELECT * FROM Table1 WHERE FieldID = 'Col3') col3
WHERE t2.col1 = col1.EnumeratedValue and t2.col2 = col2.EnumeratedValue and t2.col3 = col3.EnumeratedValue
The problem is that in our real tables there ~20 of these columns per table. I would like to find a simpler means of writing this code. I do not want to hard code 20 joins for each view that I am making. Let me know if there are any alternatives.

As with any variable join solution, a dynamic pivot is really the better way to look at this. It's not as performance as a hard-coded, non-pivot solution, but this will involve the least development hours, and can be adapted to generate view definitions rather than made into a table-valued function (which could be fed a table name and possibly column names to pivot and join)
First, the demo data setup:
if object_id('dbo.test_enum') is not null drop table dbo.test_enum
create table dbo.test_enum (
FieldID sysname
, EnumeratedValue int not null
, TextValue sysname
, primary key (FieldID, EnumeratedValue)
)
INSERT INTO dbo.test_enum
(FieldID, EnumeratedValue, TextValue)
VALUES
('Col1', 1, 'Hey'),
('Col1', 2, 'Test'),
('Col1', 3, 'George'),
('Col2', 1, 'Random'),
('Col2', 2, 'Wesley'),
('Col3', 1, 'Tompson'),
('Col3', 2, 'Oooo')
;
if object_id('dbo.test_table') is not null drop table dbo.test_table
create table test_table (
id int primary key identity(1,1)
, Col1 int not null
, Col2 int not null
, Col3 int not null
);
INSERT INTO dbo.test_table
(Col1, Col2, Col3)
VALUES
(1,2,1),
(2,1,1),
(3,1,2)
Next is the dynamic selection part:
declare #cols nvarchar(max) = (select stuff((
select ',' + quotename(c.name)
from sys.objects o
inner join sys.columns c on c.object_id = o.object_id
where o.name = 'test_table'
and c.name in ('Col1', 'Col2', 'Col3')
for xml path ('')
),1,1,''))
declare #SQL nvarchar(max) = N'
select p.id, ' + #cols + '
from (
select unp.id, unp.FieldID, e.TextValue
from dbo.test_table
unpivot (
EnumeratedValues FOR FieldID IN (' + #cols + ')
) unp
inner join dbo.test_enum e on e.EnumeratedValue = unp.EnumeratedValues
and e.FieldID = unp.FieldID
) z
pivot (
min(z.TextValue) FOR z.FieldID IN (' + #cols + ')
) p
'
exec sp_executesql #sql
On its own, this will return the result set desired in the question, but can be adapted to return view definitions of any given table/column data set, and then further adapted per table/view.

Related

combine two columns into one column rows but not same cell and categorize them

I have two tables, "TableA" for levels (Admin, Moderator, Agent ... etc) and "TableB" for users with a column indicates the level ID referring to "TableA". I want a stored procedure to categorize usernames under the levels but the result must be in one column only like this:
Those are my two tables:
TableA
+---------------------------+
|Level ID |Level Name |
+---------------------------+
|1 |Admin |
+---------------------------+
|2 |Moderator |
+---------------------------+
|3 |Agent |
+---------------------------+
TableB
+---------------------------+
|Username |Level ID |
+---------------------------+
|John |1 |
+---------------------------+
|Sam |2 |
+---------------------------+
|Tommy |2 |
+---------------------------+
|Tony |3 |
+---------------------------+
|Patrick |3 |
+---------------------------+
|Jimmy |3 |
+---------------------------+
|Tod |3 |
+---------------------------+
This is how I want the result of the query:
+-------------+
|Admin |
+-------------+
| John |
+-------------+
| |
+-------------+
|Moderator |
+-------------+
| Sam |
+-------------+
| Tommy |
+-------------+
| |
+-------------+
|Agent |
+-------------+
| Tony |
+-------------+
| Patrick |
+-------------+
| Jimmy |
+-------------+
| Tod |
+-------------+
It has to be one column only and the spaces before names can be added with
CONCAT(' ', TableA.Username)
There's an empty cell after last name in each level category.
I'm using SQL management studio 18
Use union all and order by:
select name
from ((select levelname as name, levelid, 1 as ord
from tablea
) union all
(select ' ' + username, levelid, 2 as ord
from tableb
)
) ul
order by levelid, ord;
This doesn't actually include the blank rows, which you can also include:
select name
from ((select levelname as name, levelid, 1 as ord
from tablea
) union all
(select ' ' + username, levelid, 2 as ord
from tableb
) union all
(select null, levelid, 0 as ord
from tablea
where levelid > 1
)
) ul
order by levelid, ord;
All that said. You can do this transformation in SQL. However, it is more typical to do such formatting in the application layer.
This "smells" of putting "view/output" logic into the database.. if you've got the levels and usernames via the LEFT JOIN, then iterate through the results in whatever app you're building, creating the output as you need it.....
However, here's one way of achieving what you want.... still wouldn't recommend it though
-- edit -- this is driven by data so is different to #ikram answer in that you wouldnt need to edit the stored proc as new levels are added
USE tempdb
GO
DROP TABLE IF EXISTS TableA
DROP TABLE IF EXISTS TableB
DROP TABLE IF EXISTS #wibble
GO
CREATE TABLE TableA (
levelid INTEGER
, name VARCHAR(10)
)
INSERT INTO TableA
VALUES (1, 'Admin')
, (2, 'Moderator')
, (3, 'Agent')
-- SELECT * FROM TableA
CREATE TABLE TableB (
username VARCHAR(10)
, levelid INTEGER
)
INSERT INTO TableB
VALUES ('John', 1)
, ('Sam', 2)
, ('Tommy', 2)
, ('Tony', 3)
, ('Patrick', 3)
, ('Jimmy', 3)
-- SELECT * FROM TableB
-- table to hold interim results before output
CREATE TABLE #wibble (
wobble varchar(10)
, dummyorder integer
)
-- first insert, the levels
INSERT INTO #wibble
SELECT name
, levelid * 1000 -- pick a number where the gap between numbers of users in levels is sufficient -- could be derived via count
FROM TableA
-- second insert, the users, placed "inside" the relevent level
; WITH users AS (
SELECT '---' + username as username
, levelid
, ROW_NUMBER() over (PARTITION by levelid order by username) as rn --row number of that user in that level
FROM TableB
)
INSERT INTO #wibble
SELECT username, (levelid * 1000) + rn from users
UNION ALL
SELECT null, (levelid * 1000) + rn + 1
FROM ( -- add a "dummy" row into each level, one number up from the max number of users in that level
SELECT levelid, max(rn) as rn from users
GROUP BY levelid
) AS D
-- final output
select wobble from #wibble order by dummyorder
The best way would be get the records from database and do whatever you want on code side(if you have one).
But if you want it in stored procedure and records in 'TableA' changes frequently(I don't think so) then you need to use loop. I wouldn't recommend this, because loops in queries affects query execution time.
That's why I would share a solution with hardcoded 'LevelNames' in query:
CREATE PROCEDURE sp_GetDataInOneColumn
AS
BEGIN
SELECT 'Admin'
UNION ALL
SELECT CONCAT(' ', Username) FROM TableB WHERE [Level ID] = 1
UNION ALL
SELECT ''
UNION ALL
SELECT 'Moderator'
UNION ALL
SELECT CONCAT(' ', Username) FROM TableB WHERE [Level ID] = 2
UNION ALL
SELECT ''
UNION ALL
SELECT 'Agent'
UNION ALL
SELECT CONCAT(' ', Username) FROM TableB WHERE [Level ID] = 3
END
Here is sql stored procedure with loop:
CREATE PROCEDURE sp_GetDataInOneColumnWithLoop
AS
BEGIN
CREATE TABLE #DataInOneColumn (
Names VARCHAR(MAX)
);
SELECT *
INTO #Temp
FROM TableA
DECLARE #LevelId int
DECLARE #LevelName nvarchar(100)
WHILE EXISTS(SELECT * FROM #Temp)
BEGIN
SELECT TOP 1 #LevelId = [Level ID], #LevelName = [Level Name] From #Temp ORDER BY [Level ID]
IF (EXISTS(SELECT * FROM TableB WHERE [Level ID] = #LevelId))
BEGIN
INSERT INTO #DataInOneColumn VALUES('')
INSERT INTO #DataInOneColumn VALUES(#LevelName)
INSERT INTO #DataInOneColumn SELECT CONCAT(' ', Username) FROM TableB WHERE [Level ID] = #LevelId
END
DELETE #Temp WHERE [Level ID] = #LevelId
END
SELECT Names FROM #DataInOneColumn
END

How to select only a few columns of a table

I have a Table which contain around 1000 columns. When I use
Select *
from Table
Its Return entire record of the table. But I just want only limited column of the record.
col1 | col2 | col3 | col4 | col 5 | ......................... | col1000 |
| | | | | ------------------------- | |
| | | | | ------------------------- | |
| | | | | ------------------------- | |
| | | | | ------------------------- | |
------------------------------------------------------------------------------------------------------
I just need col5 to col1000 record data only.
you have to write all the columns that you need in select
select col5, col6, ......... ,col1000 from table
there is no shot-cut way with out it and select * means all the columns of your table
If you really want to do without typing each column name, one way is using dynamic query.
For example in SQL Server you can write the dynamic query like following.
DECLARE #selstmt AS NVARCHAR(max);
SET #selstmt = 'select ' + Stuff((SELECT ', ' + Quotename(NAME) FROM
( SELECT c.NAME FROM
sys.columns c JOIN sys.tables t ON c.object_id = t.object_id
WHERE t.NAME = 'yourtablename'
AND c.NAME NOT IN('col1', 'col2', 'col3', 'col4')
)t FOR
xml path(''), type).value('.',
'NVARCHAR(MAX)'), 1, 1, '');
SET #selstmt = #selstmt + ' from yourtable'
EXEC sp_executesql #selstmt
Specify column names that you want to select instead of using * operator.
SELECT * will return all columns for table
SELECT col5, col6, col7,...., col1000 (col5 upto col1000) will return only specified columns of the table
There actually is one easy way in SSMS.
SELECT * FROM TableA
Select this text, press CNTRL SHIFT Q
Then you have all the columns and can easily remove a few.
You have to write all columns.
SELECT col1, col2, col3 from table;
But...
Tested on MySQL
Since you have too many columns, you can run a query to select the desired columns from the table:
SELECT GROUP_CONCAT(COLUMN_NAME SEPARATOR ', ')
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = 'schemaName' AND TABLE_NAME = 'table'
AND COLUMN_NAME IN ('col1', 'col2', 'col3');
# or to filter the columns
# AND COLUMN_NAME NOT IN ('col1', 'col2', 'col3');
And build the query with the resultant columns.
GROUP_CONCAT outputs the values in a single row separated with a ,, so you can use them to query the table directly
SELECT
col1,col2,col3
FROM
table_name

Import Unpivot results to new Table and match on Key

I currently have a few unpivot queries that yeilds about 2000 rows each. I need to take the results of those queires, and put in a new table to match on a key.
Query Example:
Select DeviceSlot
FROM tbl1
unpivot(
DeviceSlot
For col in(
col1,
col2,
col3,
)
)AS Unpivot
Now I need to match the results from the query, and insert it into a new table with about 20,000 rows.
Pseudo-Code for this:
Insert Into tbl2(DeviceSlot)
Select DeviceSlot
FROM tbl1
unpivot(
DeviceSlot
For col in(
col1,
col2,
col3
)
)AS Unpivot2
Where tbl1.key = tbl2.key
I've been pretty confused on how to do this, and I apologize if it is not clear.
I also have another unpivot query doing the same thing for different columns.
Not sure what you are asking for. While unpivoting to "normalize" data typically the wanted "key" is derived during the unpivot, for example, below the id column of the original table is repeated in the un-pivoted data to represent a foreign key for some new table.
SQL Fiddle
MS SQL Server 2014 Schema Setup:
CREATE TABLE Table1
([id] int, [col1] varchar(2), [col2] varchar(2), [col3] varchar(2))
;
INSERT INTO Table1
([id], [col1], [col2], [col3])
VALUES
(1, 'a', 'b', 'c'),
(2, 'aa', 'bb', 'cc')
;
Query 1:
select id as table1_fk, colheading, colvalue
from (
select * from table1
) t
unpivot (
colvalue for colheading in (col1, col2, col3)
) u
Results:
| table1_fk | colheading | colvalue |
|-----------|------------|----------|
| 1 | col1 | a |
| 1 | col2 | b |
| 1 | col3 | c |
| 2 | col1 | aa |
| 2 | col2 | bb |
| 2 | col3 | cc |

SQL Column Names from a Excel Sheet

Im using SSMS 2014 and SQL Server 2014. I need to change the column names at the end of a query result by using a excel file or table with the data.
After some SELECT statements and stuff i get a table with data for example
+---------+---------+------+
| Col1 | Col2 | Col3 |
+---------+---------+------+
| Value 1 | Value 2 | 123 |
| Value 2 | Value 2 | 456 |
| Value 3 | Value 3 | 789 |
+---------+---------+------+
And the table or excelfile
+----+---------+-----------+-----------+
| ID | ColName | Language | Addition |
+----+---------+-----------+-----------+
| 1 | Col1 | D | 123 |
| 2 | Col2 | D | 456 |
| 3 | Col3 | D | 789 |
| 4 | Col1 | E | 123 |
| 5 | Col2 | E | 456 |
| 6 | Col3 | E | 789 |
+----+---------+-----------+-----------+
What i try to do is to get the addition value of each column and add it to the column name. It should only add the values with the specific language. #setLang = 'D'
Col1 + Addition
Col2 + Addition
Col3 + Addition
+-------------+-------------+---------+
| Col1 123 | Col2 456 | Col3789 |
+-------------+-------------+---------+
| Value 1 | Value 2 | 123 |
| Value 2 | Value 2 | 456 |
| Value 3 | Value 3 | 789 |
+-------------+-------------+---------+
I tried it over Information_Schema.Columns and filter with where table = 'resultTable' and Column_name = #cName. Maybe i need a loop to get each columnname.
Thanks for reading and trying to help me.
Give this a go - it uses a table, not an excel file (but that seems to be an option in your question). I have made some temporary tables and filled them with your values, but you will obviously not need to do this. You will need to replace out the references to the tempdb with the name of the database where your tables are kept and the temp tables #Original and #ExcelInfo with your table names.
I have also used a temp table to add an 'Id IDENTITY(1,1)` Column to the table holding your original data. This is needed to keep the unpivot in check; if you can modify your table to include an Id, that will make things easier, but if not, you can insert into a temp table as I have done.
The script is shorter than it looks - the whole first bit is just setting up the example; the real answer starts at the line that declares your language variable.
/*
The script between the first two dividing lines of dashes is just used to set up the example. The bit you want is from
the "-- Test Variables --" line.
*/
-----------------------------------------------------------------------------------------------------------------------
IF OBJECT_ID('tempdb..#Original') IS NOT NULL DROP TABLE #Original
IF OBJECT_ID('tempdb..#ExcelInfo') IS NOT NULL DROP TABLE #ExcelInfo
CREATE TABLE #Original
( Col1 VARCHAR(50)
,Col2 VARCHAR(50)
,Col3 VARCHAR(50))
CREATE TABLE #ExcelInfo
( Id INT IDENTITY(1,1) NOT NULL
,ColName VARCHAR(50) NOT NULL
,[Language] CHAR(1) NOT NULL
,Addition INT NOT NULL)
INSERT #Original
SELECT *
FROM
( SELECT 'Value 1' AS Col1,'Value 2' AS Col2 ,123 AS Col3
UNION SELECT 'Value 2' ,'Value 2' ,456
UNION SELECT 'Value 3' ,'Value 3' ,789) AS This
ORDER BY Col1
INSERT #ExcelInfo (ColName,[Language],Addition)
SELECT *
FROM
( SELECT 'Col1' AS ColName, 'D' AS [Language], 123 AS Addition
UNION SELECT 'Col2','D',456
UNION SELECT 'Col3','D',789
UNION SELECT 'Col1','E',123
UNION SELECT 'Col2','E',456
UNION SELECT 'Col3','E',789) AS This
ORDER BY [Language], Addition
-----------------------------------------------------------------------------------------------------------------------
-- Test Variables --
DECLARE #SetLang CHAR(1) = 'D'
-----------------------------------------------------------------------------------------------------------------------
-- make the default empty, not null on our dynamic string, so it can be added to
DECLARE #Columns VARCHAR(MAX) = ''
DECLARE #SQL VARCHAR(MAX)
CREATE TABLE #OriginalColumns
( Id INT IDENTITY(1,1)
,Name VARCHAR(50))
CREATE TABLE #BasicResult
(Id INT NOT NULL, Name VARCHAR(50), Value VARCHAR(50))
-- If you can add an id column to your original table, this bit is unecessary - you can use yours in place of this table
CREATE TABLE #Original_WITH_Id
( Id INT IDENTITY(1,1)
,Col1 VARCHAR(50)
,Col2 VARCHAR(50)
,Col3 VARCHAR(50))
INSERT #Original_WITH_Id
SELECT * FROM #Original
-----------------------------------------------------------------------------------------------------------------------
-- List out the columns and put the list in a variable.
INSERT #OriginalColumns
SELECT QUOTENAME(Col.name)
FROM tempdb.sys.columns AS Col
WHERE Col.object_id = OBJECT_ID('tempdb.dbo.#Original_WITH_Id')
-- we're not interested in the identity column at the moment
AND Col.name <> 'Id'
-- keep everything in the same order as they are listed on the table
ORDER BY Col.column_id
SELECT #Columns = #Columns + ',' + Name
FROM #OriginalColumns
-- clip off the leading comma
SELECT #Columns = SUBSTRING(#Columns,2,LEN(#Columns))
-- get a full list of everything, creating our new list of columns as we go, using the Id column to keep a mark on which
-- row each record originally came from
SET #SQL =
'INSERT #BasicResult
SELECT Id, New.Name, Value FROM
(SELECT Id, Name, Value
FROM #Original_WITH_Id
UNPIVOT (Value FOR Name IN (' + #Columns + ')) Unpvt) AS Old
JOIN (SELECT ColName, CONVERT(VARCHAR(50),ColName) + '' '' + CONVERT(VARCHAR(50),Addition) AS Name
FROM #ExcelInfo
WHERE [Language] = ''' + #SetLang + ''') AS New ON Old.Name = New.ColName'
PRINT #SQL
EXEC (#SQL)
-- now update our list of columns to be the new column headings
SET #Columns = ''
SELECT #Columns = #Columns + ',' + QUOTENAME(Name) FROM (SELECT DISTINCT Name FROM #BasicResult) AS Names
SELECT #Columns = SUBSTRING(#Columns,2,LEN(#Columns))
-- pivout our results back out to their original format, but with the new column headings (include the Id if you want)
SET #SQL =
'SELECT /*Id,*/ ' + #Columns + '
FROM
(SELECT Id, Name,Value
FROM #BasicResult) AS Up
PIVOT (MAX(Value) FOR Name IN (' + #Columns + ')) AS Pvt'
PRINT #SQL
EXEC (#SQL)
-- clean up --
DROP TABLE #OriginalColumns
DROP TABLE #BasicResult
Hope that helps! There may be a more efficient way to do this... I'm not sure.
Okay i tried it again but now without the Excelfile. I made a CSV out of the Excelfile and insert it with Bulk to my created Table:
IF NOT EXISTS(SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'CSVTest')
BEGIN
CREATE TABLE _DICTIONARY
( _TableName VARCHAR (20),
_ColumnName VARCHAR (20),
_Language VARCHAR (20),
_FieldShort VARCHAR (50),
_FieldMid VARCHAR (50),
_FieldLong VARCHAR (50)
)
BULK
INSERT _DICTIONARY
FROM 'C:\_DICTIONARY.csv'
WITH
(
FIELDTERMINATOR = ';',
ROWTERMINATOR = '\n'
)
END
After that i rename all Columns by using a Cursor
DECLARE #dic_tableName as nvarchar(50),
#dic_columnName as nvarchar(50),
#db_tableName as nvarchar(50),
#db_columnName as nvarchar(50);
DECLARE C CURSOR FAST_FORWARD FOR
SELECT _TableName, _ColumnName FROM _DICTIONARY
OPEN C;
FETCH NEXT FROM C INTO #dic_tableName, #dic_columnName;
WHILE ##FETCH_STATUS = 0
BEGIN
IF EXISTS(SELECT TABLE_NAME, COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = #dic_tableName AND COLUMN_NAME = #dic_columnName)
BEGIN
SET #db_tableName = #dic_tableName + '.' + #dic_columnName
SET #db_columnName = #dic_tableName + '_' + #dic_columnName
EXEC sp_rename #db_tableName, #db_columnName ,'COLUMN'
FETCH NEXT FROM C INTO #dic_tableName, #dic_columnName;
END
ELSE
BEGIN
FETCH NEXT FROM C INTO #dic_tableName, #dic_columnName;
END
END
CLOSE C;
DEALLOCATE C;
Its doing its job.

Pivot and merge columns in a SQL Server stored procedure

I have a table with the following columns
Col1(bigint) | Col2(datetime)| Col3(nvarchar(100))| Col4(xml)
The 4th column is a xml which looks like following, it may contain any number of fields
<Fields>
<Field1>10</Field1>
<Field2>11</Field2>
<Field3>10</Field3>
<Field4>11</Field4>
</Fields>
I need to query multiple rows from the table. I am creating a stored procedure which gets 2 parameters
Parameter1: #query (type of xml)
<Rowset>
<Row>
<Col1>20140510123205321</Col1>
<Col2>2014-05-14T13:01:03.1426856+05:30</Col2>
<Col3>Source1</Col3>
</Row>
<Row>
<Col1>20140510123205322</Col1>
<Col2>2014-05-14T13:01:03.1426856+05:30</Col2>
<Col3>Source2</Col3>
</Row>
</Rowset>
Parameter2: #Fields (type of string comma separated)
Field1,Field2,Field3,Field4
I am expecting a output in the following format
Col1 | Col2 | Col3 | Field1 | Field2 | Field3 | Field4
-----------------------------------------------------------------
2014051092|2014-05-14|Source1| 10 | 21 | 12 | 43
2014051093|2014-05-14|Source1| 11 | 22 | 23 | 53
I have created a table from the first parameter in the stored procedure.
INSERT INTO #TempPricing
(
Col1,
Col2,
Col3
)
SELECT
Col1,
Col2,
Col3
FROM OPENXML(#handle, '/Rowset/Row', 2)
WITH
(
Col1 bigint,
Col2 datetime,
Col3 varchar(50)
)
How can I pivot the second parameter after splitting, merge it with the table above and fetch the data?
EDIT
The output can also be the following format
Col1 | Col2 | Col3 | Fields
--------------------------------------
2014051092|2014-05-14|Source1|<Fields><Field1>10</Field1><Field1>11</Field1></Fields>
2014051093|2014-05-14|Source1|<Fields><Field1>20</Field1><Field1>21</Field1></Fields>
so any of the above formats will work
Lets try the below script it may help you.
declare #String varchar(max), #Result varchar(max)
select #String= COALESCE(#String+',', '')+ QUOTENAME(Col1)
FROM (
select distinct Col1 from TableA A Inner Join dbo.Tab C VS on A.AttributeID =VS.AttributeId)AS B
set #Result ='
with pivotData AS
(
select distinct P.Col1, PA.col1,A.Col1,PA.col2 from Tab3 PA join Attribute A
on A.AttributeID=PA.AttributeID join Product P on P.ProductId=PA.ProductId
)
select Col1, Col2,
'+#String+' from pivotData
pivot(
Max(col2) for
Col1in('+#String+')
)as PR order by col3 desc'
exec (#Result)