I want to display rows as column in SQL Server.
My table looks like this:
images_id item_id images_name
-------------------------------
1 1 image1.jpg
2 1 image2.jpg
3 1 image3.jpg
4 2 image4.jpg
5 2 image5.jpg
6 2 image6.jpg
I'd like this output:
images_id item_id image1 image2 image3
------------------------------------------------------
1 1 image1.jpg image2.jpg image3.jpg
2 2 image4.jpg image5.jpg image6.jpg
Here is an image link.
Is this possible or not? item_id must be dynamically changeable (it is not stable).
Cross Tabs and Pivots, Part 1 – Converting Rows to Columns
Cross Tabs and Pivots, Part 2 - Dynamic Cross Tabs
Pivot table for Microsoft SQL Server
This isn't possible without using dynamic SQL. PIVOT requires you to specify the columns still.
Let me know if dynamic SQL is acceptable and I'll spin you an example.
Here is how you can use Dynamic SQL for this:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
SET #cols = STUFF((SELECT distinct ',' + QUOTENAME('image' + cast(row_number() over(partition by itemid order by imageid) as varchar(5)))
FROM test c
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT itemid, ' + #cols + ' from
(
select itemid, imagename,
''image'' + cast(row_number() over(partition by itemid order by imageid) as varchar(5)) col
from test
) x
pivot
(
min(imagename)
for col in (' + #cols + ')
) p '
execute(#query)
See SQL Fiddle with Demo
Related
I was able to find information on how to separate a comma delineated strings into columns here: How Do I Split a Delimited String in SQL Server Without Creating a Function? - but it doesn't quite solve my problem.
The data I am working with is a list of interests/activities for a given record. For instance, a record would have 'yoga, hiking' etc... At present we have 63 distinct activities total but we also need to accommodate for activities that do not yet exist.
What I've been tasked with is creating an automated process which:
Creates a new column in the table for each activity listed (and creates new columns as presently non-existent activities are added)
Have the columns reflect the name of the activity
If the record contains an activity, the column for that activity has a Y in it.
Ultimately, the outcome would look something like this...
id | activities | art | yoga | music | hiking | ...
-----------------------------------------------------------
1 | yoga, hiking | NULL | y | NULL | y | ...
2 | art, music, yoga | y | y | y | NULL | ...
Thank you in advance for any help that can be provided, let me know if any more information is required.
There are two concepts to learn here.
First, you have to split the string into rows. xquery is the fastest method on large recordsets, albeit more difficult to write.
Then you need to use a dynamic pivot to put the activities into new columns.
I've provided two outputs below, just pick which suites your needs best.
Xquery Example
Dynamic Pivot Example
Code sample:
if OBJECT_ID('tempdb..#tmp') is not null drop table #tmp
if OBJECT_ID('tempdb..#tmpsplit') is not null drop table #tmpsplit
declare #cols nvarchar(MAX), #sql nvarchar(MAX)
create table #tmp (id int identity(1,1), activities varchar(255))
insert into #tmp (activities)
values ('yoga, hiking'),
('art, music, yoga')
/* split activities into individual rows and store in #tmpsplit*/
SELECT DISTINCT A.ID,
ltrim(rtrim(Split.a.value('.', 'VARCHAR(max)'))) AS activity
into #tmpsplit
FROM (SELECT id,
CAST ('<M>' + REPLACE(CAST(activities AS VARCHAR), ',', '</M><M>') + '</M>' AS XML) AS String
FROM #tmp) AS A
CROSS APPLY String.nodes ('/M') AS Split(a)
WHERE LEN(Split.a.value('.', 'VARCHAR(max)'))>1
/* create list of activities to pivot */
SET #cols = STUFF((SELECT distinct ',' + QUOTENAME(c.activity)
FROM #tmpsplit c
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)') ,1,1,'')
/* create pivot: id and columns only*/
set #sql = 'select id, ' + #cols + '
from (select s.*, ''y'' as val
from #tmpsplit s) datatable
pivot (max(val) for activity in (' + #cols + ')
) p '
print(#sql)
exec(#sql)
/* create pivot: id, full activitites string, and columns*/
set #sql = 'select id, activities, ' + #cols + '
from (select s.*, t.activities, ''y'' as val
from #tmpsplit s
join #tmp t on s.id=t.id) datatable
pivot (max(val) for activity in (' + #cols + ')
) p '
print(#sql)
exec(#sql)
This question already has answers here:
Efficiently convert rows to columns in sql server
(5 answers)
Closed 7 years ago.
I've been reading the various examples on this board but haven't been able to whip up a dynamic pivot query to fit my code. Any help would be appreciated!
I have two tables
AuxDef
Fieldnumber Fieldlabel
------------------------
1 Buyer
2 Size Range
3 Source
4 Country
5 Vendor
ect... ect...
AuxFields
PageID FieldNumber TextValue
-----------------------------------
1 1 Sam
1 2 S-L
1 3 Domestic
1 4 Canada
2 1 Kyla
2 3 Import
2 5 VendorName
2 6 Off-Shore
2 7 Fit 1
2 8 Yes
4 1 Sara
4 3 Import
4 4 China
ect.. ect.. ect..
What I would like to do is create a dynamic pivot that joins the two tables by fieldnumber and uses the fieldlabels as the column headers after pageid. It would look similar to this.
PageID Buyer Size Range Source Country Vendor Type Status Exclusive ect..
------------------------------------------------------------------------------------------------
1 Sam S-L Domestic Canada
2 Kyla Import VendorName Off-Shore Fit 1 Yes
4 Sara Import China
I've tried examples on this site but I keep running into errors either when I replace the fields with my own or in the actual column generation.
You will need to create a dynamic pivot (credit to #bluefeet's answer here) something like this:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX);
SET #cols = STUFF((SELECT distinct ',' + QUOTENAME(c.FieldLabel)
FROM auxdef c
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT PageID, ' + #cols + ' from
(
select
PageId,
FieldLabel,
TextValue
from AuxFields af
inner join auxdef ad on af.FieldNumber = ad.FieldNumber
) x
pivot
(
max(TextValue)
for FieldLabel in (' + #cols + ')
) p '
execute(#query);
SQL Fiddle Demo
Here's another way
sql fiddle
declare #sql nvarchar(max)
select #sql = 'select af.pageId'
select #sql = #sql + ', max(case when ad.fieldLabel = ''' + ad.fieldLabel + ''' then af.textValue end) as [' + ad.fieldLabel + ']' + char(13)
from auxDef ad
select #sql = #sql + 'from auxDef ad' + char(13)
+ 'inner join auxFields af on af.fieldNumber = ad.fieldNumber' + char(13)
+ 'group by af.pageId'
exec(#sql)
I am going to do some arthimetic calulation for particular Id with two different category code.
So i have the below two row as input,
I am expecting the below output as,
I am trying to do some self join but i am not luckly getting the desired output.
Can you pls help me out here?
Note: Only two row will come for particular ID (Two type of categories will come [A or C]).
Only two row will come for particular ID (Two type of categories will
come [A or C]).
Then this query should be sufficient:
SELECT ID,
ValueA = SUM(CASE WHEN Category = 'A' THEN Value END),
ValueC = SUM(CASE WHEN Category = 'C' THEN Value END)
FROM dbo.TableName
GROUP BY ID
Sql-Fiddle
Method 1:
Try this
SELECT *
FROM Table1
Pivot (MAX(value) for Category in ([A],[C])) as Value
Fiddle Demo
Output:
+-------------+-------+-------+
| ID | A |C |
+-------------+-------+-------+
| WD559606479 | 0.748 |2.088 |
+-------------+-------+-------+
Method 2: Dynamic Pivot
If you have one more column in the input then
Try this
DECLARE #cols AS NVARCHAR(MAX)
DECLARE #query AS NVARCHAR(MAX)
SET #cols = STUFF((SELECT distinct ',' + QUOTENAME(c.category)
FROM table1 c
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
SET #query ='SELECT id, ' + #cols + ' from
(
SELECT id
, category
, value
FROM table1
) x
Pivot
(
Max(value)
For category In (' + #cols + ')
) P'
Execute(#query)
Fiddle Demo
Output:
+-------------+-------+-------+
| ID | A |C |
+-------------+-------+-------+
| WD559606479 | 0.748 |2.088 |
+-------------+-------+-------+
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
SQL Server dynamic PIVOT query?
I have a dataset that has the below structure.
CREATE TABLE #TempTable
(
Measure_ID INT,
measurement DECIMAL(18, 4)
)
INSERT INTO #TempTable
VALUES
(1,2.3)
,(1,3.4)
,(1,3.3)
,(2,3)
,(2,2.3)
,(2,4.0)
,(2,4.5)
I need to produce output that will look like this.
1,2.3,3.4,3.3
2,3,2.3,4.0,4.5
Basically its a pivot on Measure_ID. Unfortunately, there can be an unlimited number of measure_id's. So Pivot is out.
I'm hoping to avoid CURSORS, but will if that turns out to be the best approach.
If you have an unknown number of values, then you can use a PIVOT with dynamic SQL:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT distinct ','
+ QUOTENAME('Measurement_' + cast(rn as varchar(10)))
from temptable
cross apply
(
select row_number() over(partition by measure_id order by measurement) rn
from temptable
) x
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT measure_id, ' + #cols + ' from
(
select measure_id, measurement,
''Measurement_''
+ cast(row_number() over(partition by measure_id order by measurement) as varchar(10)) val
from temptable
) x
pivot
(
max(measurement)
for val in (' + #cols + ')
) p '
execute(#query)
See SQL Fiddle With Demo
If you have a known number of values, then you can hard-code the values, similar to this:
SELECT measure_id, [Measurement_1], [Measurement_2],
[Measurement_3], [Measurement_4]
from
(
select measure_id, measurement,
'Measurement_'
+ cast(row_number() over(partition by measure_id order by measurement) as varchar(10)) val
from temptable
) x
pivot
(
max(measurement)
for val in ([Measurement_1], [Measurement_2],
[Measurement_3], [Measurement_4])
) p
See SQL Fiddle With Demo
Both queries will produce the same results:
MEASURE_ID | MEASUREMENT_1 | MEASUREMENT_2 | MEASUREMENT_3 | MEASUREMENT_4
==========================================================================
1 | 2.3 | 3.3 | 3.4 | (null)
2 | 2.3 | 3 | 4 | 4.5
I have a bunch of data (multiple rows for each unique reference) that needs to be in one row with multiple columns. Some of columns that need to be used have to be further split out as they hold more than one value. This has been done using an unpivot. I now have 7 columns from this 1 original column and it now needs to display statuses against the new 7 columns. I cannot however use a pivot as I need to see the various statuses in the 7 columns and not a min, max or a count.
You can perform this type of shift with a PIVOT function.
Static Pivot (See SQL Fiddle for Demo):
select *
from
(
select reference, jobtypesplit, status
from t1
) x
pivot
(
min(status)
for jobtypesplit in ([DDS], [MBN], [LPN], [WEN], [LLP], [OPE], [SSE])
) p
This can also be done dynamically (See SQL Fiddle)
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT distinct ',' + QUOTENAME(jobtypesplit)
FROM t1
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT reference, ' + #cols + ' from
(
select reference, jobtypesplit, status
from t1
) x
pivot
(
min(status)
for jobtypesplit in (' + #cols + ')
) p '
execute(#query)