Pivot table with one row and four columns - sql-server

-- Pivot table with one row and four columns
SELECT 'Values' tValues,
ID,Name,ValueID,Value FROM (
Select ID,Name,ValueID,Value FROM Table WHERE OptionID = 1000000
) AS SourceTable
PIVOT (
COUNT(tValues)
FOR tValues IN ( ID,Attribute,ValueID,Value )
) AS PivotTable;
I'm going off the example at Microsoft.com: http://msdn.microsoft.com/en-us/library/ms177410.aspx
But there are a few things about Pivot i don't really understand, so don't be surprised when you see it in the code above, such as COUNT(tValues), I have no idea what this is for, by judging from the example on microsoft, it seems to be always some sort of numeric value, so i figured i'd try it to see if it would return something, but all it returns is an error. Anyhow, if someone out there can share why this query doesn't work, and possibly explain what the numeric value above the FOR is used for?
The Table containts an x amount of rows, with four columns, so it looks like this:
ID | Name | ValueID | Value
100 | Color | 10000 | Black
101 | Size | 10005 | Large
The output should be like this:
Name_100 | Color | Name_101 | Size |
10000 | Black | 10005 | Large |

Something like this maybe.
This will only work if the name column is unique. If not then you might want to append an id on it.
So first some test data:
CREATE TABLE tblValues
(
ID INT,
Name VARCHAR(100),
ValueID INT,
Value VARCHAR(100)
)
INSERT INTO tblValues
VALUES
(100,'Color',10000,'Black'),
(101,'Size',10005,'Large')
Then you need to get the columns to pivot on:
DECLARE #cols VARCHAR(MAX)
;WITH CTE AS
(
SELECT
'Name_'+CAST(tbl.ID AS VARCHAR(100)) AS Name,
'Name_'+CAST(tbl.ID AS VARCHAR(100)) AS Sort,
tbl.ID
FROM
tblValues AS tbl
UNION ALL
SELECT
tbl.Name,
'Value_'+CAST(tbl.ID AS VARCHAR(100)) AS Sort,
tbl.ID
FROM
tblValues AS tbl
)
SELECT
#cols = COALESCE(#cols + ','+QUOTENAME(Name),
QUOTENAME(Name))
FROM
CTE
ORDER BY
CTE.ID,
CTE.Sort
Then declaring and executing the dynamic sql like this:
DECLARE #query NVARCHAR(4000)=
N'SELECT
*
FROM
(
SELECT
''Name_''+CAST(tbl.ID AS VARCHAR(100)) AS pivotName,
CAST(tbl.ValueID AS VARCHAR(100)) AS name
FROM
tblValues AS tbl
UNION ALL
SELECT
tbl.Name AS pivotName,
tbl.Value AS name
FROM
tblValues AS tbl
) AS p
PIVOT
(
MAX(name)
FOR pivotName IN ('+#cols+')
) AS pvt'
EXECUTE(#query)
Then in my case I will drop the table I have created
DROP TABLE tblValues
Edit
Or in you case it should be something like this:
First the columns:
DECLARE #cols VARCHAR(MAX)
;WITH CTE AS
(
SELECT
'Name_'+CAST(tbl.ID AS VARCHAR(100)) AS Name,
'Name_'+CAST(tbl.ID AS VARCHAR(100)) AS Sort,
tbl.ID
FROM
[Table] AS tbl
WHERE
tbl.OptionID = 1000000
UNION ALL
SELECT
tbl.Name,
'Value_'+CAST(tbl.ID AS VARCHAR(100)) AS Sort,
tbl.ID
FROM
[Table] AS tbl
WHERE
tbl.OptionID = 1000000
)
SELECT
#cols = COALESCE(#cols + ','+QUOTENAME(Name),
QUOTENAME(Name))
FROM
CTE
ORDER BY
CTE.ID,
CTE.Sort
Then the dynamic sql.
DECLARE #query NVARCHAR(4000)=
N'SELECT
*
FROM
(
SELECT
''Name_''+CAST(tbl.ID AS VARCHAR(100)) AS pivotName,
CAST(tbl.ValueID AS VARCHAR(100)) AS name
FROM
[Table] AS tbl
WHERE
tbl.OptionID = 1000000
UNION ALL
SELECT
tbl.Name AS pivotName,
tbl.Value AS name
FROM
[Table] AS tbl
WHERE
tbl.OptionID = 1000000
) AS p
PIVOT
(
MAX(name)
FOR pivotName IN ('+#cols+')
) AS pvt'
EXECUTE(#query)
You do not need to create the table or drop the table. That was just because I did not have your table in my database and that if someone else want's to run the example.

If you want to use Pivot tables with a variable number of columns, then I'd suggest using something along the lines of;
DECLARE #cols VARCHAR(4000)
DECLARE #query VARCHAR(8000)
SELECT #cols = STUFF(( SELECT DISTINCT
'],[' + Name
FROM Table
ORDER BY '],[' + Name
FOR XML PATH('')
), 1, 2, '') + ']'
SET #query =
'SELECT * FROM
(
SELECT col1, col2, col3, whateverColYourInterestedIn, Name, Value
FROM Table
)t
PIVOT (MAX(Value) FOR Name
IN ('+#cols+')) AS pvt'
EXECUTE (#query)
That is probably not quite right, but it should hopefully be a starting point for you.
For more info, check out links such as this or this.

Related

Dynamic Pivot multiple columns in SQL Server

I have a table like this
Id Name FromAddress ToAddress
1 Joey ABC JKL
2 Joey DEF MNP
3 Joey GHI OQR
I am looking for the following output with dynamic pivot in SQL Server
Name FromAdrs1 FromAdrs2 FromAdrs3 ToAdrs1 ToAdrs2 ToAdrs3
Joey ABC DEF GHI JKL MNP OQR
Note: The number of rows changes based on the Id value, so I am trying to get the output using dynamic Pivot.
Here is the code that I tried, it's looks like it is correct, but throwing me an error.
IF OBJECT_ID('temp..#temp') IS NOT NULL
DROP TABLE #temp
CREATE TABLE #temp
(
Id INT, Name VARCHAR(10), FromAddress VARCHAR(10), ToAddress VARCHAR(10)
)
INSERT INTO #temp VALUES (1, 'Joey', 'ABC', 'JKL'), (2, 'Joey', 'DEF', 'MNP'), (3, 'Joey', 'GHI', 'OQR')
--SELECT * FROM #temp
DECLARE #colsFrom AS NVARCHAR(MAX),
#colsTo AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX);
SET #colsFrom = STUFF((SELECT distinct ',' + QUOTENAME(CONVERT(VARCHAR(2), t.id) + 'From')
FROM #temp t
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
SET #colsTo = STUFF((SELECT distinct ',' + QUOTENAME(CONVERT(VARCHAR(2), t.id) + 'To')
FROM #temp t
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT *, ' + #colsFrom + ', ' + #colsTo + ' from
(
select *
from #temp
) T
PIVOT
(
max(FromAddress)
for Id in (REPLACE('''+#colsFrom+''',''From'',''''))
) p
PIVOT
(
max(ToAddress)
for Id in (REPLACE('''+#colsTo+''',''To'',''''))
) Q'
execute(#query)
DROP TABLE #temp
Any help is appreciated. Thank you all for your time.
Edit: This is the error
I believe the problem is the IN () expression in the PIVOTs. The column list explicitly has to be a list of fields names, not a function and not a list of varchar literals or function values. You've got a REPLACE() function in there. The engine expects to be looking for a field named [REPLACE] and then gets confused by the open parentheses that shows up.
This is valid (square brackets for emphasis):
SELECT VendorID, Employee, Orders
FROM
(SELECT VendorID, Emp1, Emp2, Emp3, Emp4, Emp5
FROM pvt) p
UNPIVOT
(Orders FOR Employee IN
([Emp1], [Emp2], [Emp3], [Emp4], [Emp5])
)AS unpvt;
This is not:
SELECT VendorID, Employee, Orders
FROM
(SELECT VendorID, Emp1, Emp2, Emp3, Emp4, Emp5
FROM pvt) p
UNPIVOT
(Orders FOR Employee IN
('Emp1', 'Emp2', 'Emp3', 'Emp4', 'Emp5')
)AS unpvt;
And this is not valid:
SELECT VendorID, Employee, Orders
FROM
(SELECT VendorID, Emp1, Emp2, Emp3, Emp4, Emp5
FROM pvt) p
UNPIVOT
(Orders FOR Employee IN
(REPLACE('Emp1','1','A'), REPLACE('Emp2','2','B'))
)AS unpvt;
Replace the execute(#query) with a select #query or print #query to see the query your code generated and troubleshoot the syntax in a query analyzer that way. Then work backwards.
You want to do the REPLACE() at the same level you're building the query. The query that ends up in the #query variable should already have the column names fixed.
Alternately, you could generate #colsFromLabels, #colsToLabels, #colsFrom and #colsTo with the former two have the 'from' and to bits added and the latter two just being column names.
Your desired output is a little gross as far as square bracket escaping, too.
ok, I created a temp table to do some testing on. The solution requires an unpivot first. I recommend running with/without the extra test data to get a sense of some other behaviors that surround this solution -- the weirdness that comes with the MAX aggregation and lack of new rows that you might have expected when changing the value in 'name'.
GL. Hope it helps.
-------------------------
-- Some test data here
CREATE table #addresses ( Id int, Name varchar(5), FromAddress varchar(5), ToAddress varchar(5))
insert into #addresses(id, Name, FromAddress, ToAddress) Values
(1,'Joey', 'ABC', 'JKL')
, (2,'Joey', 'DEF', 'MNO')
, (3,'Joey', 'GHI', 'PQR')
, (4,'Spike', 'XXX', 'YYY')
, (1,'Spike', 'QQQ', 'RRR')
-------------------------
-- Solution starts here. create a temp table and unpivot your data into it.
-- Your initial technique of does not work, PIVOT only supports one aggregation
CREATE table #unpvt(RowColCode varchar(20), vals varchar(20))
Insert into #unpvt
SELECT ColCode + '_' + Cast(ID as varchar(2)) as RowColCode, vals
FROM #addresses a
UNPIVOT
(vals for ColCode in (Name,FromAddress,ToAddress)) c
-------------------------
-- Read the temp table for a column list
declare #ColList nvarchar(max)
set #ColList = STUFF((
SELECT distinct ',[' + t.RowColCode + ']'
FROM #unpvt t
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)'),1,1,'')
-------------------------
-- 're pivot' the data using your new column list
declare #qry varchar(max)
set #qry = '
select *
from
#unpvt
PIVOT(
MAX(vals)
FOR RowColCode in (' +#ColList + ')
) rslt
'
execute(#qry)

Pivot total for column and row not showing correct value

honestly, for several days, i am trying to learn about pivot table behavior. rightnow, i am able to display sum of row and column in pivot table. Here is the code that i am trying to set
DECLARE #cols AS NVARCHAR(MAX)
DECLARE #colswithNoNulls AS NVARCHAR(MAX)
DECLARE #query AS NVARCHAR(MAX)
DECLARE #tanggal_awal DATE
DECLARE #tanggal_akhir DATE
DECLARE #print NVARCHAR(MAX)
DECLARE #querycount AS NVARCHAR(MAX)
CREATE TABLE #datatable
(
product_id int,
product_date date,
product_ammount int
)
SET #tanggal_awal = convert(DATE,'02-01-2017')
SET #tanggal_akhir = convert(DATE,DATEADD(dd,-1,(DATEADD(mm,1,#tanggal_awal))))
--SELECT DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,GETDATE())+1,0))
INSERT INTO #datatable (product_id,product_date,product_ammount) VALUES
(1,GETDATE(),100),
(1,GETDATE(),900),
(2,DATEADD(DD,-1,GETDATE()),400),
(3,DATEADD(DD,4,GETDATE()),300),
(1,DATEADD(DD,4,GETDATE()),200),
(2,DATEADD(DD,2,GETDATE()),700),
(4,DATEADD(DD,-3,GETDATE()),1000),
(4,DATEADD(MM,1,GETDATE()),200),
(4,GETDATE(),750)
;WITH CTE (datelist,maxdate) AS
(
SELECT CONVERT(INT,(MIN(DATEPART(day,#tanggal_awal)))) datelist, CONVERT(INT,MAX(DATEPART(day,product_date))) maxdate
FROM #datatable
UNION ALL
SELECT CONVERT(INT,(DATEPART(day,datelist))), CONVERT(INT,(DATEPART(day,#tanggal_akhir)))
FROM cte
WHERE datelist < maxdate
) SELECT c.datelist
INTO #temp
FROM cte c
ORDER BY c.datelist
OPTION (maxrecursion 0)
SELECT #cols = STUFF((SELECT ',' + QUOTENAME(CONVERT(int, datelist))
FROM #temp
GROUP BY datelist
ORDER BY CONVERT(int, datelist)
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,''
)
SELECT #colswithNoNulls = STUFF((SELECT ',ISNULL(' + QUOTENAME(CONVERT(int, datelist)) +',''0'') '+ QUOTENAME(CONVERT(int, datelist))
FROM #temp
GROUP BY datelist
ORDER BY CONVERT(int, datelist)
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
SET #query =
'SELECT product_id, '+ #colswithNoNulls+', Total FROM
(
select
ISNULL((CAST(b.product_id as nvarchar(30))), ''Total'') product_id,
coalesce(b.product_ammount,0) as product_ammount,
DATEPART(dd,(convert(CHAR(10), product_date, 120))) PivotDate,
SUM(product_ammount) over (partition by b.product_id) as Total
FROM #datatable b
WHERE product_date between #tanggal_awal and #tanggal_akhir
GROUP BY product_ammount,product_date,product_id
WITH ROllup
) x
pivot
(
sum(product_ammount)
for PivotDate in (' +#cols+ ')
) p
ORDER BY CASE when (product_id = ''Total'') then 1 else 0 end, product_id'
EXECUTE sp_executesql #query ,N'#tanggal_awal DATE, #tanggal_akhir DATE', #tanggal_awal,#tanggal_akhir
IF(OBJECT_ID('tempdb.dbo.#temp','U') IS NOT NULL)
BEGIN
TRUNCATE TABLE #temp
TRUNCATE TABLE #datatable
DROP TABLE #temp
DROP TABLE #datatable
END
ELSE
BEGIN
SELECT '#temp is not created in this script' AS MESSAGE
END
as you can see , the result is show on the display. However, the total value at the very right bottom is strange since it is like doubled up exact total value like in this picture:
How to resolve this issue btw? since it was bit confusing for me. thank you for your help :)
Generally, I am not fully aware for RollUp functionality. From your PIVOT query. I have found some of the empty rows is coming up (basically subtotal rows from "With Rollup" option), so I have modified the Group by statement a little bit to achieve the expected result.
select
ISNULL((CAST(b.product_id as nvarchar(30))), 'Total') product_id,
coalesce(b.product_ammount,0) as product_ammount,
DATEPART(dd,(convert(CHAR(10), product_date, 120))) PivotDate,
SUM(product_ammount) over (partition by b.product_id) as Total
FROM #datatable b
WHERE product_date between #tanggal_awal and #tanggal_akhir
GROUP BY product_ammount,product_date,ROllup(product_id)
Kindly replace this query in PIVOT, then you will get the desired output.
Note: Sorry I am not fully aware of RollUp functionality, so I'm unable to give the right explanation.

Split Data and transforming them into Columns

I have an Input table as under
Id Data
1 Column1: Value1
2 Column2: Value11
3 Column3: Value111
4 Column1: Value2
5 Column2: Value22
6 Column3: Value222
I am looking for an output as under
Column1 Column2 Column3
Value1 Value11 Value111
Value2 Value22 Value222
How can I achieve so? It could have been done easily by using a WHILE LOOP and by a bit of mathematical logic, but I am looking for a more optimized one if possible by only SELECT queries (no LOOPS).
I have tried also by splitting using (':') as delimiter and then transforming ROWS to COLUMNS (PIVOT) but somewhat could not be able to proceed. (That's my thought, peoples may have more better thoughts).
My shot so far
Declare #t table(Id int identity(1,1),Data varchar(1000))
Insert into #t Values
('Column1: Value1'),('Column2: Value11'),('Column3: Value111')
,('Column1: Value2'),('Column2: Value22'),('Column3: Value222')
Select *
FROM #t
SELECT
F1.id,
F1.Data,
O.splitdata
FROM
(
SELECT *,
cast('<X>'+replace(F.Data,':','</X><X>')+'</X>' as XML) as xmlfilter from #t F
)F1
CROSS APPLY
(
SELECT fdata.D.value('.','varchar(50)') as splitdata
FROM f1.xmlfilter.nodes('X') as fdata(D)) O
This will work if you want a pure SQL solution:
Select [Column1], [Column2], [Column3] From (
Select col, val, id = ROW_NUMBER() over(partition by d.col order by d.id)
From (
Select id
, col = LEFT(Data, CHARINDEX(':', Data)-1)
, val = RIGHT(Data, LEN(DATA) - CHARINDEX(':', Data))
From #t
) as d
) as p
pivot(
MAX(val)
FOR col in([Column1], [Column2], [Column3])
) as piv
But it supposes that data for Row 1 are always before data for Row 2. There is no way to distinguish them using your sample.
If the number of column is not fixed, it has to use Dynamic SQL.
SQL Server may not be the best options for this kind of thing.
With Dynamic SQL, the above query would be like this one:
create table #t(Id int identity(1,1),Data varchar(1000))
Insert into #t Values
('Column1: Value1'),('Column2: Value11'),('Column3: Value111')
,('Column1: Value2'),('Column2: Value22'),('Column3: Value222')
Declare #sql nvarchar(max)
Select #sql = '
Select '+left(c, len(c)-1)+' From (
Select col, val, id = ROW_NUMBER() over(partition by d.col order by d.id)
From (
Select id
, col = LEFT(Data, CHARINDEX('':'', Data)-1)
, val = RIGHT(Data, LEN(DATA) - CHARINDEX('':'', Data))
From #t
) as d
) as p
pivot(
MAX(val)
FOR col in('+left(c, len(c)-1)+')
) as piv
'
From (
Select Distinct '['+LEFT(Data, CHARINDEX(':', Data)-1)+'], '
From #t
FOR XML PATH('')
) as d(c)
EXEC sp_executesql #sql
SQL Fiddle
This should work:
Declare #t table(Id int identity(1,1),Data varchar(1000))
Insert into #t Values
('Column1: Value1'),('Column2: Value11'),('Column3: Value111')
,('Column1: Value2'),('Column2: Value22'),('Column3: Value222');
WITH Splitted AS
(
SELECT *
,CAST('<X>'+REPLACE(F.Data,':','</X><X>')+'</X>' AS XML) AS xmlfilter
FROM #t AS F
)
SELECT p.*
FROM
(
SELECT ROW_NUMBER() OVER(PARTITION BY xmlfilter.value('X[1]','varchar(max)') ORDER BY Id) AS Inx
,xmlfilter.value('X[1]','varchar(max)') AS ColName
,xmlfilter.value('X[2]','varchar(max)') AS ColVal
FROM Splitted
) AS tbl
PIVOT
(
MAX(ColVal) FOR ColName IN(Column1,Column2,Column3)
) AS p

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)

pivot table how to create the following

i have table like this
DisposalID ReportID
242 84
243 84
i want to see it following way
DisposalID DisposalID ReportID
242 243 84
i tried using pivot table but could not achieve that
select
*
from
(
SELECT [DisposalID]
,[ReportID]
FROM [ClearData_Test].[dbo].[DisposalConsolidatedView] WHERE [ReportID]=84
) DataTable
PIVOT
(
Min(disposalid)
FOR reportid
IN ([84])
) PivotTable
its only gives me min or max. Any help would be greatly appriciated.
Since PIVOT requires aggregation, your current query will only return the min/max value of each DisposalId. In order to get the result that you want you have to create column that will be used as your new column headers.
I would use row_number() and partition the data by your ReportId. The subquery that you are using would be altered slightly to the following:
SELECT [DisposalID]
,[ReportID]
, 'DisposalId'
+cast(row_number() over(partition by reportId
order by disposalid) as varchar(10)) seq
FROM [dbo].[DisposalConsolidatedView]
WHERE [ReportID]=84
See SQL Fiddle with Demo. This is going to create a column with the values DisposalId1 and DisposalId2 - these new values will be your new column headers and then you will apply the aggregate to your existing DisposalId column.
The final syntax will be:
select DisposalId1, DisposalId2, ReportId
from
(
SELECT [DisposalID]
,[ReportID]
, 'DisposalId'
+cast(row_number() over(partition by reportId
order by disposalid) as varchar(10)) seq
FROM [dbo].[DisposalConsolidatedView]
WHERE [ReportID]=84
) DataTable
PIVOT
(
Min(disposalid)
FOR seq IN (DisposalId1, DisposalId2)
) PivotTable;
See SQL Fiddle with Demo. This will give a result:
| DISPOSALID1 | DISPOSALID2 | REPORTID |
|-------------|-------------|----------|
| 242 | 243 | 84 |
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT distinct ',' + QUOTENAME('DisposalID'+cast(seq as varchar(10)))
from
(
select row_number() over(partition by [reportId]
order by disposalid) seq
from [ClearData_Test].[dbo].[DisposalConsolidatedView]
) d
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT [ReportID],' + #cols + '
from
(
SELECT [ReportID], disposalid,
''disposalid''+
cast(row_number() over(partition by [reportId]
order by disposalid) as varchar(10)) seq
FROM [ClearData_Test].[dbo].[DisposalConsolidatedView]
where[ReportID]=''84''
) x
pivot
(
Min(disposalid)
for seq in (' + #cols + ')
) p '
execute sp_executesql #query;
That was the solution I was looking for.

Resources