I have a table with 3 columns.
The column color can be dynamic, now I have 4 elements, after I can get 6 elements or more.
How to write query to do this ?
Thank you
You can use dynamic sql like:
CREATE TABLE #t
(
Company CHAR(3) ,
Value INT ,
color NVARCHAR(10)
)
GO
DECLARE #c NVARCHAR(MAX) = '['
DECLARE #s NVARCHAR(MAX) = ''
INSERT INTO #t
VALUES ( 'AAA', 2, 'red' ),
( 'AAA', 2, 'white' ),
( 'BBB', 2, 'white' ),
( 'BBB', 3, 'blue' ),
( 'CCC', 3, 'pink' ),
( 'FFF', 4, 'blue' )
SELECT #c = #c + color + '],['
FROM ( SELECT DISTINCT
color
FROM #t
) AS t
SELECT #c = SUBSTRING(#c, 1, LEN(#c) - 2)
SET #s = ';WITH cte AS
(
SELECT Company, Value, color FROM #t
)
SELECT Company, ' + #c + ' FROM cte
PIVOT(MAX(Value) FOR color IN(' + #c + ')) AS p'
EXEC(#s)
Output:
Company blue pink red white
AAA NULL NULL 2 2
BBB 3 NULL NULL 2
CCC NULL 3 NULL NULL
FFF 4 NULL NULL NULL
Apply appropriate aggregation in pivot clause.
Using PIVOT. Learn SQL SERVER – PIVOT and UNPIVOT Table Examples
SELECT Company, red, white, blu, pink
FROM TableName
PIVOT(MAX(Value) FOR Color IN(ed, white, blu, pink))AS Piv
Dynamic Pivot:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX);
SET #cols = STUFF((SELECT distinct ',' + QUOTENAME(c.Color)
FROM TableName c
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT Company, ' + #cols + ' from
(
select Company
, value
, color
from TableName
) x
pivot
(
max(value)
for color in (' + #cols + ')
) p '
execute(#query)
Related
I have following SQL script which I hope to cross apply to select Chinese column name
CREATE TABLE #temp([color] varchar(5), [size] varchar(5),[AQty] varchar(10),[BQty] varchar(10),[CQty] varchar(10),[DQty] varchar(10));
INSERT INTO #temp([color], [size], [AQty], [BQty],[CQty],[DQty])
VALUES ('A1', 'L','1','2','3','4')
, ('A1', 'M','1','2','3','4')
, ('A1', 'S','1','2','3','4')
, ('A1', 'XL','1','2','3','4')
, ('B1', 'L','1','2','3','4')
, ('B1', 'M','1','2','3','4')
, ('B1', 'S','1','2','3','4')
, ('B1', 'XL','1','2','3','4')
, ('B1', 'XXL','1','2','3','4')
, ('C1', 'L','1','2','3','4')
, ('C1', 'S','1','2','3','4')
declare #cols as varchar(max), #sql varchar(max)
select #cols = STRING_AGG(col, ', ') from (
select distinct QUOTENAME(size) as col from #temp
) as t
set #sql = '
select color, col as total, ' + #cols + '
from(
select color, size, col, [value]
from #temp
cross apply (
select ''总数一'', cast(AQty as varchar(10)) union all
select ''总数二'', cast(BQty as varchar(10)) union all
select ''总数三'', cast(CQty as varchar(10)) union all
select ''总数四'', cast(DQty as varchar(10))
) c(col, [value])
) d
pivot
(
max(value)
for size in (' + #cols + ')
) piv
order by color, total
'
exec(#sql)
But now exec SQL is display garbled when I hope to display Chinese column name
color total L M S XL XXL
A1 ??? 4 4 4 4 NULL
B1 ??? 4 4 4 4 4
C1 ??? 4 NULL4 NULLNULL
I tried to change it like this, change variable nvarchar, set #sql with N and change cross apply select with N, but now not work.
declare #cols as nvarchar(max), #sql nvarchar(max)
set #sql = N'
select color, col as total, ' + #cols + '
from(
select color, size, col, [value]
from #temp
cross apply (
select N''总数一'', cast(AQty as varchar(10)) union all
select N''总数二'', cast(BQty as varchar(10)) union all
select N''总数三'', cast(CQty as varchar(10)) union all
select N''总数四'', cast(DQty as varchar(10))
) c(col, [value])
) d
pivot
(
max(value)
for size in (' + #cols + ')
) piv
order by color, total
'
exec(#sql)
I have solved my problem by adding N after + #cols +
declare #cols as nvarchar(max), #sql nvarchar(max)
set #sql = N'
select color, col as total, ' + #cols + N'
from(
select color, size, col, [value]
from #temp
cross apply (
select N''总数一'', cast(AQty as varchar(10)) union all
select N''总数二'', cast(BQty as varchar(10)) union all
select N''总数三'', cast(CQty as varchar(10)) union all
select N''总数四'', cast(DQty as varchar(10))
) c(col, [value])
) d
pivot
(
max(value)
for size in (' + #cols + ')
) piv
order by color, total
'
exec(#sql)
SQL Query Table:
Date Production LineName Buyer Style
2021-04-30 100 A Lev 1a
2021-04-30 200 B Kont 2d
2021-04-30 300 C ABB 4l
2021-04-30 400 A Lev 1a
2021-04-29 600 A BDA 3z
Output need like:
LineName 2021-04-29 2021-04-30
A 600,BDA,3Z 500,Lev,1a
B NULL 200,Kont,2d
C NULL 300,ABB,4l
I started coding and stuck at
DECLARE #query VARCHAR(4000)
,#Dates VARCHAR(4000)
SET #Dates = STUFF((
SELECT DISTINCT '],[' + Cast([Date] As Varchar)
FROM Table_17M
ORDER BY '],[' + Cast([Date] As Varchar)
FOR XML PATH('')
), 1, 2, '') + ']'
SET #query = ';With PivotData
As
(
Select
LineName, -- grouping element
[Date], -- spreading element
PlanProduction-- aggregating element
From Table_17M
)
Select *
From PivotData
Pivot (Sum(PlanProduction) For [Date] In (' + #Dates + ')) As P;'
EXEC (#query);
Any idea please share. It will very much helpful. Thanks.
If you are using SQLServer 2017 or later version then use string_agg() instead of suff(). It's easier to implement and much faster.
select #cols= string_agg(quotename([date]),',') from (select distinct [date] from Table_17M)t
DB-Fiddle
create table Table_17M(Date Date,Production int, LineName varchar(50), Buyer varchar(50), Style varchar(50));
insert into Table_17M values('2021-04-30', 100, 'A', 'Lev', '1a');
insert into Table_17M values('2021-04-30', 200, 'B', 'Kont', '2d');
insert into Table_17M values('2021-04-30', 300, 'C', 'ABB' , '4l');
insert into Table_17M values('2021-04-30', 400, 'A', 'Lev' , '1a');
insert into Table_17M values('2021-04-29', 600, 'A', 'BDA' , '3z');
Query:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
SET #cols = STUFF((SELECT distinct ',' + quotename([date])
FROM Table_17M
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'select LineName , ' + #cols + ' from
(
select LineName,[date],concat(sum(production),'','',max(buyer),'','',string_agg(Style,'','')) other_columns
from Table_17M
group by LineName,[date]
) x
pivot
(
max(other_columns)
for [date] in (' + #cols + ')
) p
group by LineName , ' + #cols
execute( #query)
Output:
LineName
2021-04-29
2021-04-30
A
600,BDA,3z
500,Lev,1a,1a
B
null
200,Kont,2d
C
null
300,ABB,4l
db<fiddle here
Example query which I used
Declare #DataColumn table (id int not null primary key identity(1,1), ColumnName Nvarchar(250),DataValue Nvarchar(250))
insert into #DataColumn
select DataColumnName, DataValue
from CustomObjectMappingTable obm
join #price_tmp temp on obm.ObjectFieldName = temp.FieldName
where temp.DataValue <> ''
select * from #DataColumn
Result is :
id ColumnName DataValue
-------------------------
1 Column_1 Umar Mehmood
2 Column_2 27
3 Column_3 21-nov-1992
4 Column_4 Male
5 Column_5 Gujar Khan District RWP
I have data into temp table and I need to insert into physical table using temp table. I want to use from temptable first columndata as " ColumnName" and second column data as "Data" how can I do this any one help me please?
Query for inserting
insert into CustomData (#DataColumn.ColumnName)
select *
from
(select DataValue, ColumnName
from #DataColumn) d
pivot
(max(DataValue)
for ColumnName in (ColumnName)
) piv;
Need it dynamically
Try the following:
DECLARE #DataColumn table ( id int, ColumnName varchar(50), DataValue varchar(50) );
INSERT INTO #DataColumn VALUES
( 1, 'Column_1', 'Umar Mehmood' ),
( 2, 'Column_2', '27' ),
( 3, 'Column_3', '21-nov-1992' ),
( 4, 'Column_4', 'Male' ),
( 5, 'Column_5', 'Gujar Khan District RWP' );
DECLARE #insert_columns varchar(MAX) = (
SELECT STUFF(
( SELECT ',[' + ColumnName + ']' FROM #DataColumn ORDER BY id FOR XML PATH( '' ) ),
1,
1,
''
)
);
DECLARE #insert_values varchar(MAX) = STUFF ( (
SELECT ',(' + STUFF(
( SELECT ',''' + DataValue + '''' FROM #DataColumn ORDER BY id FOR XML PATH( '' ) ),
1,
1,
''
) + ')'
), 1, 1, '' );
DECLARE #tsql varchar(MAX) = 'INSERT INTO CustomData (' + #insert_columns + ') VALUES ' + #insert_values + ';';
--EXEC(#tsql); -- Uncomment this line to execute the dynamic SQL.
PRINT #tsql;
The printed dynamic SQL:
INSERT INTO CustomData ([Column_1],[Column_2],[Column_3],[Column_4],[Column_5]) VALUES ('Umar Mehmood','27','21-nov-1992','Male','Gujar Khan District RWP');
We can do it using pivot table for dynamically
DECLARE #cols NVARCHAR(MAX), #query NVARCHAR(MAX) , #DataValues NVARCHAR(max);
SET #cols = STUFF( (SELECT DISTINCT ','+QUOTENAME(ColumnName) FROM ##DataColumn c FOR XML PATH(''), TYPE ).value('.', 'nvarchar(max)'), 1, 1, '');
SET #query = 'SELECT * from ( select [ColumnName],[DataValue] from ##DataColumn
) as sourcetable pivot (max(DataValue) for[ColumnName] in ('+#cols+')) p order by 1 ';
Insert into customdata ( [Column_1],[Column_2],[Column_3],[Column_4],[Column_5])
SELECT * from ( select [ColumnName],[DataValue] from #DataColumn ) as sourcetable
pivot (max(DataValue) for[ColumnName] in ([Column_1],[Column_2],[Column_3],[Column_4],[Column_5])) p order by 1
Imagine I have this table:
Column A | Column B | Column C
------------------------------
111 X 10
111 Y 12
How can I query this table to show the results like these:
Column A | X | Y
-----------------------------------
111 10 12
You can perform this via a PIVOT. You can use either a static PIVOT where you know the number of columns that you want to rotate or you can use a dynamic PIVOT
Static Pivot (see SQL Fiddle with Demo)
SELECT *
FROM
(
select *
from t1
) x
pivot
(
min(columnc)
for columnb in ([X], [Y])
) p
Dynamic Pivot (see SQL Fiddle with Demo)
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX);
select #cols = STUFF((SELECT distinct ',' + QUOTENAME(columnb)
from t1
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT columna, ' + #cols + ' from
(
select *
from t1
) x
pivot
(
min(ColumnC)
for ColumnB in (' + #cols + ')
) p '
execute(#query)
Both versions will give the same results. The second works when you have an unknown number of columns that will be transformed.
Try:
DECLARE #tbl TABLE (ColumnA INT, ColumnB CHAR(1), ColumnC INT)
INSERT #tbl VALUES (111, 'X', 10), (111, 'Y', 12)
SELECT *
FROM #tbl
PIVOT
(
MAX(ColumnC) FOR ColumnB IN ([X], [Y])
) pvt
I have table in SQL Server 2005 that contains two columns Fruit and Colour as shown below
Fruit Colour
Apple Red
Orange Red
Berry Green
PineApple Green
Now i want to convert it into an adjacency matrix query
as shown below
Red Green
Apple 1 0
Orange 1 0
Berry 0 1
PineApple 0 1
what i want to do is give 1 if Fruit and Colour are there
else i want to give a 0
Here is an example:
CREATE TABLE #Fruits (name varchar(10), color varchar(10))
GO
INSERT #Fruits VALUES ('Apple', 'Red')
INSERT #Fruits VALUES ('Orange', 'Red')
INSERT #Fruits VALUES ('Berry', 'Green')
INSERT #Fruits VALUES ('PineApple', 'Green')
GO
DECLARE #select_query nvarchar(4000);
DECLARE table_cursor CURSOR
FOR SELECT DISTINCT color FROM #Fruits;
DECLARE #color varchar(10);
SET #select_query = N'SELECT name'
OPEN table_cursor;
FETCH NEXT FROM table_cursor INTO #color;
WHILE ##FETCH_STATUS = 0
BEGIN
SET #select_query = #select_query + N', CASE WHEN color = ''' + #color + N''' THEN 1 ELSE 0 END AS ' + #color;
FETCH NEXT FROM table_cursor INTO #color;
END
CLOSE table_cursor;
DEALLOCATE table_cursor;
SET #select_query = #select_query + N' FROM #Fruits';
EXEC sp_executesql #select_query
Find distinct colors
Build SELECT statment
Execute it via sp_executesql
try dynamic Pivot. (I Assumed your table's name is t1)
like this:
declare #sql nvarchar(max)
set #sql = ''
select #sql = #sql +'['+Colour +'],'
from
(select distinct colour from t1) t2
set #sql = substring(#sql,1,len(#sql) - 1)
set #sql = '
select * from(
select Fruit, Colour, 1 as CheckMark from t1
) as t2
pivot
(
SUM(CheckMark)
for Colour in ('+#sql+')
) as pivotTable'
execute (#sql)
this query returns NULL instead of 0.
hope I helped
It was hard to avoid those null values in the pivot.
declare #t table (fruit varchar(10), colour varchar(10))
insert #t
select 'Apple', 'Red' union all
select 'Orange', 'Red' union all
select 'Berry', 'Green' union all
select 'PineApple', 'Green'
select * from (
select a.fruit, b.colour, case when c.fruit is null then 0 else 1 end found from
(select distinct fruit, colour from #t) a
cross join
(select distinct colour from #t) b
left outer join
(select distinct fruit, colour from #t) c
on a.fruit = c.fruit and b.colour = c.colour) d
PIVOT
(max(found)
FOR colour
in([red],[green])
)AS p
order by 3, 1
Output
fruit red green
---------- ----------- -----------
Apple 1 0
Orange 1 0
Berry 0 1
PineApple 0 1
SELECT Fruit,
CASE WHEN Colour = 'Red' THEN 1 ELSE 0 END AS Red
CASE WHEN Colour = 'Green' THEN 1 ELSE 0 END AS Green
FROM [TABLE_NAME]
CREATE TABLE #t(fruit VARCHAR(10), colour VARCHAR(10))
INSERT #t
SELECT 'Apple', 'Red' UNION ALL
SELECT 'Orange', 'Red' UNION ALL
SELECT 'Berry', 'Green' UNION ALL
SELECT 'PineApple', 'Green'
DECLARE #pivot_columns VARCHAR(2000)
SET #pivot_columns = ''
SELECT #pivot_columns = #pivot_columns + '[' + colour + '],'
FROM (SELECT DISTINCT colour FROM #t)t
SET #pivot_columns = LEFT(#pivot_columns, LEN(#pivot_columns) - 1)
PRINT #pivot_columns
DECLARE #sql VARCHAR(MAX)
SET #sql = '
SELECT fruit, ' + #pivot_columns + '
FROM
(
SELECT fruit, colour
FROM #t
) AS SourceTable
PIVOT
(
COUNT(colour)
FOR Colour IN (' + #pivot_columns + ')
) AS PivotTable'
PRINT #sql
EXEC (#sql)
DROP TABLE #t
It is possible to keep dynamic nature of Maziar Taheri's answer and get rid of nulls:
if object_id('tempdb..#t') is not null
drop table #t
create table #t (fruit varchar(10), colour varchar(10))
insert #t
select 'Apple', 'Red' union all
select 'Apple', 'Green' union all
select 'Apple', 'Yellow' union all
select 'Apple', 'Yellow' union all
select 'Orange', 'Red' union all
select 'Orange', 'Yellow' union all
select 'Berry', 'Green' union all
select 'Berry', 'Red' union all
select 'Berry', 'Black' union all
select 'PineApple', 'Green'
declare #sql nvarchar(max), #colours nvarchar(max)
select #sql = '', #colours = ''
select #colours = #colours +'['+Colour +'],',
#sql = #sql +'isnull(['+Colour+'],0) '+Colour+','
from
(select distinct colour from #t) t2
set #colours = substring(#colours,1,len(#colours) - 1)
set #sql = substring(#sql,1,len(#sql) - 1)
select #sql = '
select Fruit,'+#sql +' from
(
select Fruit, Colour, 1 as CheckMark from #t
) as t2
pivot
(
SUM(CheckMark)
for Colour in ('+#colours+')
) as pivotTable'
execute (#sql)