Pivot with Group by on SQL - sql-server

I'm create sql syntax which create pivot Group By Product based on Category
CREATE TABLE #Product ( Product varchar(10),Category varchar(10),Stock int)
INSERT INTO #Product Values ('Item A','CatA',10)
INSERT INTO #Product Values ('Item A','CatB',5)
INSERT INTO #Product Values ('Item B','CatA',3)
INSERT INTO #Product Values ('Item B','CatB',5)
INSERT INTO #Product Values ('Item B','CatC',7)
INSERT INTO #Product Values ('Item B','CatD',10)
SELECT *
FROM
(
SELECT Product,Category,Stock
FROM #Product A
) src
pivot
(
SUM(Stock)
for Category in ([CatA], [CatB], [CatC],[CatD])
) piv;
DROP TABLE #Product
Result of Query
Product CatA CatB CatC CatD
Item A 10 5 NULL NULL
Item B 3 5 7 10
Result trying to achieve is
Product Cat1 Stock1 Cat2 Stock2 Cat3 Stock3 Cat4 Stock4
Item A CatA 10 CatB 5 CatC 0 CatD 0
Item B CatA 3 CatB 5 CatC 7 CatD 10
Thanks for the help

You need to create all combinations of Product and Category first. Then do a LEFT JOIN on #Product to get the Stock. Finally, use the result to pivot the data.
Since I'm not familiar with the PIVOT command, I used another technique called Dynamic Crosstab
DECLARE #sql NVARCHAR(MAX) = N'';
SELECT #sql =
'SELECT
Product' + CHAR(10);
SELECT #sql = #sql +
STUFF((
SELECT
' ,MAX(CASE WHEN RN = ' + CONVERT(VARCHAR(3), t.RN) + ' THEN Category END) AS ' + QUOTENAME('Cat' + CONVERT(VARCHAR(3), t.RN)) + CHAR(10) +
' ,MAX(CASE WHEN RN = ' + CONVERT(VARCHAR(3), t.RN) + ' THEN Stock END) AS ' + QUOTENAME('Stock' + CONVERT(VARCHAR(3), t.RN)) + CHAR(10)
FROM (
SELECT DISTINCT
RN = ROW_NUMBER() OVER(PARTITION BY Product ORDER BY(SELECT NULL))
FROM #Product
) t
FOR XML PATH('')
), 1, 1, ' ');
SELECT #sql = #sql +
'FROM(
SELECT
p1.Product,
p1.Category,
Stock = ISNULL(p2.Stock, 0),
RN = ROW_NUMBER() OVER(PARTITION BY p1.Product ORDER BY p1.Category)
FROM (
SELECT
t1.Product, t2.Category
FROM (
SELECT DISTINCT Product FROM #Product
) t1
CROSS JOIN (
SELECT DISTINCT Category FROM #Product
) t2
) p1
LEFT JOIN #Product p2
ON p1.Product = p2.Product
AND p1.Category = p2.Category
)t
GROUP BY Product;';
PRINT #sql;
EXEC sp_executesql #sql;
ONLINE DEMO

Related

How To Select specific column As Row?

I have 2 tables Phone_record and customer
In my phone records tables I have two columns company_name and ModelNo
Now I want to show Company_name as my main column name
And in this column I want to show models of that company like this
Company 1 company2.....
Model1 model1
Model2 model2
How to write this query?
Here is a fully functional example of how you might do this.
if OBJECT_ID('tempdb..#Something') is not null
drop table #Something
create table #Something
(
ID int,
Subject1 varchar(50)
)
insert #Something
select 10868952, 'Some Subject' union all
select 10868952, 'Another one' union all
select 10868952, 'This Subject' union all
select 10868952, 'Science' union all
select 12345, 'My Subject'
declare #MaxCols int
declare #StaticPortion nvarchar(2000) =
'with OrderedResults as
(
select *, ROW_NUMBER() over(partition by ID order by Subject1) as RowNum
from #Something
)
select ID';
declare #DynamicPortion nvarchar(max) = '';
declare #FinalStaticPortion nvarchar(2000) = ' from OrderedResults Group by ID order by ID';
with E1(N) AS (select 1 from (values (1),(1),(1),(1),(1),(1),(1),(1),(1),(1))dt(n)),
E2(N) AS (SELECT 1 FROM E1 a, E1 b), --100 rows
cteTally(N) AS
(
SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E2
)
select #DynamicPortion = #DynamicPortion +
', MAX(Case when RowNum = ' + CAST(N as varchar(6)) + ' then Subject1 end) as Subject' + CAST(N as varchar(6)) + CHAR(10)
from cteTally t
where t.N <=
(
select top 1 Count(*)
from #Something
group by ID
order by COUNT(*) desc
)
--select #StaticPortion + #DynamicPortion + #FinalStaticPortion
declare #SqlToExecute nvarchar(max) = #StaticPortion + #DynamicPortion + #FinalStaticPortion;
exec sp_executesql #SqlToExecute

How to pivot columns in SQL Server

I'm new to SQL Server and I am trying to pivot rows into columns
select SalesOrExpense, store_no, total
from myTable
SalesOrExpense Store_No total ($)
-------------------------------------
Expense 22 100
Sales 22 400
to look like this
Store_No Expense Sales
---------------------------------
22 100 400
Could someone help point me in the right direction?
Thanks
We can even do it by executing dynamic sql query..
Query
declare #sql as varchar(max);
select #sql = stuff((
select ', sum(case [SalesOrExpense] when ' + char(39) +
[SalesOrExpense] + char(39) +
' then [total] else 0 end) as [' + [SalesOrExpense] + ']'
from [your_table_name]
for xml path('')
)
, 1, 2, ''
);
select #sql = 'select [Store_No], ' + #sql +
' from [your_table_name] group by [Store_No];';
exec(#sql);
CREATE TABLE #Table1
([SalesOrExpense] varchar(7), [Store_No] int, [total] int)
;
INSERT INTO #Table1
([SalesOrExpense], [Store_No], [total])
VALUES
('Expense', 22, 100),
('Sales', 22, 400)
select *
from
(
select *
from #Table1
) src
pivot
(
max(total)
for SalesOrExpense in ([Expense], [Sales])
) piv;
CREATE TABLE #Table1
([SalesOrExpense] varchar(7), [Store_No] int, [total] int);
INSERT INTO #Table1
([SalesOrExpense], [Store_No], [total])
VALUES
('Expense', 22, 100),
('Sales', 22, 400);
SELECT Store_No,
SUM(CASE WHEN SalesOrExpense='Expense' THEN TOTAL END) AS Expense,
SUM(CASE WHEN SalesOrExpense='Sales' THEN TOTAL END) AS Sales
FROM #table1 GROUP BY Store_No;
OUTPUT:-
-------------------------
Store_No | Expense |Sales
---------------------------
22 100 400

how shall i transpose rows into new columns only if duplicates appears in rows?

I have a table like this:
I need to get output like this:
I tried to use transposing, but I am not getting someone please give idea to do this.
Creation script for table:
CREATE TABLE #T1 (
itemid int,
pack int,
UOM nvarchar(2)
)
INSERT INTO #T1 VALUES
(1,1,'EA'),
(1,10,'BX'),
(1,100,'CA'),
(2,1,'EA'),
(2,10,'RL')
If you need simple, fixed column solution, you can use:
SELECT * INTO #temp FROM
(VALUES
(1, 1, 'EA'),
(1, 10, 'BX'),
(1, 100, 'CA'),
(2, 1, 'EA'),
(2, 10, 'RL')) T(ItemId, Pack, UOM)
SELECT ItemId, MAX([1]) Pack1, MAX([U1]) UOM1, MAX([2]) Pack1, MAX([U2]) UOM1, MAX([3]) Pack1, MAX([U3]) UOM1 FROM
(
SELECT *,
ROW_NUMBER() OVER (PARTITION BY ItemId ORDER BY Pack) PackNum,
'U'+CONVERT(varchar(10), ROW_NUMBER() OVER (PARTITION BY ItemId ORDER BY Pack)) UOMNum
FROM #temp
) T
PIVOT
(
MAX(Pack) FOR PackNum IN ([1], [2], [3])
) PPack
PIVOT
(
MAX(UOM) FOR UOMNum IN ([U1],[U2],[U3])
) PUOM
GROUP BY ItemId
If number of columns is not fixed, you must do it dynamically (see #gofr1) or:
DECLARE #count TABLE(N varchar(10))
INSERT #count
SELECT CONVERT(varchar(10), ROW_NUMBER() OVER (ORDER BY (SELECT 1)))
FROM #temp WHERE ItemId =
(
SELECT TOP 1 ItemId
FROM #temp
GROUP BY ItemId
ORDER BY COUNT(*) DESC
)
DECLARE #select varchar(MAX) = STUFF((SELECT ', MAX(['+N+']) Pack'+N+', MAX([U'+N+']) UOM'+N FROM #count FOR XML PATH('')), 1, 2, '')
DECLARE #pivot1 varchar(MAX) = STUFF((SELECT ', ['+N+']' FROM #count FOR XML PATH('')), 1, 2, '')
DECLARE #pivot2 varchar(MAX) = STUFF((SELECT ', [U'+N+']' FROM #count FOR XML PATH('')), 1, 2, '')
DECLARE #sql varchar(MAX) = '
SELECT ItemId, '+#select+' FROM
(
SELECT *,
ROW_NUMBER() OVER (PARTITION BY ItemId ORDER BY Pack) PackNum,
''U''+CONVERT(varchar(10), ROW_NUMBER() OVER (PARTITION BY ItemId ORDER BY Pack)) UOMNum
FROM #temp
) T
PIVOT
(
MAX(Pack) FOR PackNum IN ('+#pivot1+')
) PPack
PIVOT
(
MAX(UOM) FOR UOMNum IN ('+#pivot2+')
) PUOM
GROUP BY ItemId'
EXEC(#sql)
Dynamic SQL and some pivoting:
DECLARE #sql nvarchar(max),
#columns nvarchar(max)
SELECT #columns = (
SELECT DISTINCT ','+QUOTENAME('pack' + cast(ROW_NUMBER() OVER (PARTITION BY itemid ORDER BY itemid) as nvarchar(max)))+','+
QUOTENAME('UOM'+ cast(ROW_NUMBER() OVER (PARTITION BY itemid ORDER BY itemid) as nvarchar(max)))
FROM #T1
FOR XML PATH('')
)
SELECT #sql = N'
SELECT *
FROM (
SELECT itemid,
Items+rn as Items,
[Values]
FROM (
SELECT itemid,
CAST(UOM as nvarchar(max)) as UOM,
CAST(pack as nvarchar(max)) as pack,
CAST(ROW_NUMBER() OVER (PARTITION BY itemid ORDER BY (SELECT NULL)) as nvarchar(max)) as rn
FROM #T1
) as t
UNPIVOT (
[Values] FOR Items in ([UOM],[pack])
) as up
) t1
PIVOT (
MAX([Values]) FOR Items IN ('+STUFF(#columns,1,1,'')+')
) as pvt'
EXEC sp_executesql #sql
Output:
itemid pack1 UOM1 pack2 UOM2 pack3 UOM3
1 1 EA 10 BX 100 CA
2 1 EA 10 RL NULL NULL
EDIT#1
There is one more way:
DECLARE #sql nvarchar(max),
#columns nvarchar(max),
#colsrn nvarchar(max)
;WITH cte AS (
SELECT DISTINCT cast(ROW_NUMBER() OVER (PARTITION BY itemid ORDER BY itemid) as nvarchar(max)) as rn
FROM #T1
)
SELECT #columns = (
SELECT ',MAX('+QUOTENAME('pack' + rn) +') as '+ QUOTENAME('pack' + rn) +',MAX('+
QUOTENAME('UOM'+ rn) +') as ' + QUOTENAME('UOM'+ rn)
FROM cte
FOR XML PATH('')
),
#colsrn = (
SELECT DISTINCT ',CASE WHEN rn = ' + rn +' THEN '+QUOTENAME('pack')+' ELSE NULL END as [pack'+rn+'],'
+'CASE WHEN rn = ' + rn +' THEN '+QUOTENAME('UOM')+' ELSE NULL END as [UOM'+rn+']'
FROM cte
FOR XML PATH('')
)
SELECT #sql = N'
SELECT itemid'+#columns+'
FROM (
SELECT itemid'+#colsrn+'
FROM (
SELECT *,
ROW_NUMBER() OVER (PARTITION BY itemid ORDER BY (SELECT NULL)) as rn
FROM #T1
) as t
) s
GROUP BY s.itemid'
EXEC sp_executesql #sql
Same output.
select itemid,
max(case when seq = 1 then pack end) pack1, max(case when seq = 1 then uom end)uom1,max(case when seq = 2 then pack end) pack2, max(case when seq = 2 then uom end) uom2,
max(case when seq = 3 then pack end) pack3, max(case when seq = 3 then uom end) uom3
from
(
select itemid, pack, uom, row_number() over(partition by itemid order by itemid) seq from T1
) d
group by itemid

T sql pivot table selecting for IN

I have below query for pivot table only for products 0 , 3 , 11
SELECT *
FROM (
SELECT
year(createdDate) as [year],month(createdDate) as [month],cp.product_Id as product_ID,
cp.salesprice as Amount
FROM customer_products cp
) as s
PIVOT
(
SUM(Amount)
FOR [product_Id] IN ([0],[3],[11]) -- for 0 , 3 , 11 products
)AS a
I have also Product table as below
ProductID int
ProductName varchar(50)
Question:
How can i use ( I want to select all ProductID from Product table)
select ProductID from Product
as below
SELECT *
FROM (
SELECT
year(createdDate) as [year],month(createdDate) as [month],cp.product_Id as product_ID,
cp.salesprice as Amount
FROM customer_products cp
) as s
PIVOT
(
SUM(Amount)
FOR [product_Id] IN (select ProductID from Product) -- How can ı select all product ID here as select * from Product ?
)AS a
You have to use DYNAMIC PIVOT something like this:
DECLARE #cols AS NVARCHAR(MAX) = '',
#sql AS NVARCHAR(MAX)
SELECT #cols += N'' + QUOTENAME(ProductID) + ', '
FROM (
SELECT DISTINCT ProductID
FROM Product
) a
SET #cols = LEFT(#cols, LEN(#cols) - 1)
SET #sql = N'SELECT * FROM
(
SELECT
year(createdDate) as [year],month(createdDate) as [month],cp.product_Id as product_ID,
cp.salesprice as Amount
FROM customer_products cp
) x
PIVOT
(
SUM(Amount)
FOR [product_Id] IN (' + #cols + ')
) p
EXEC Sp_executesql #sql

SQL - How to insert multiple records as one record without pivot?

i want to create a query from multiple records as one record , but i don't want to use Pivot, is there any solutions?
here's the table :
ID Element_Name Value
1 Parmitha 100
2 Anggun 200
3 Chandra 300
4 BagusofTerror 400
and i want the result is like this :
paramitha , anggun, chandra , bagusofterror
100 , 200, 300, 400
You can use for xml path ('') to transpose the values of a column.
For example, you could write
select Element_Name + ', '
from TheTable
for xml path ('');
To get Parmitha, Anggun, Chandra, BagusofTerror,
Here's a live demo: http://www.sqlfiddle.com/#!3/71f88/24
You can also use COALESCE to pivot a results set of columns into a varchar variable:
CREATE TABLE #Pivot
(ID int, Element_Name varchar(50), Value int)
INSERT #Pivot values (1,'Parmitha',100)
INSERT #Pivot values (2,'Anggun',200)
INSERT #Pivot values (3,'Chandra',300)
INSERT #Pivot values (4,'BagusofTerror',400)
DECLARE #titles VARCHAR(1000)
DECLARE #values VARCHAR(1000)
SET #titles = ''
SET #values = ''
SELECT #titles = #titles + COALESCE(Element_Name + ',' , '')
FROM #Pivot ORDER BY ID
SELECT #values = #values + COALESCE(convert(varchar, Value) + ',' , '')
FROM #Pivot ORDER BY ID
SELECT #titles
UNION ALL
SELECT #values
Gives:
Parmitha,Anggun,Chandra,BagusofTerror,
100,200,300,400,
Try this :-
Select
MAX(CASE WHEN colID = 1 THEN value ELSE NULL END) AS [Parmitha],
MAX(CASE WHEN colID = 2 THEN value ELSE NULL END) AS [Anggun],
MAX(CASE WHEN colID = 3 THEN value ELSE NULL END) AS [Chandra],
MAX(CASE WHEN colID = 4 THEN value ELSE NULL END) AS [BagusofTerror]
FROM
(
SELECT ROW_NUMBER() OVER (ORDER BY ID) AS colID,
ID,
Element_Name,
value
FROM Sample
) AS d
SQL DEMO
Taking Wolf's answer into consideration ,using dynamic query and xml path
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT distinct ','
+ convert(varchar(max), Element_Name, 120)
from Sample
FOR XML PATH(''), TYPE
).value('.', 'varchar(MAX)')
,1,1,'')
set #query = 'SELECT' + #cols + ' from
(
select value, Element_Name
from Sample
) x
pivot
(
max(value)
for Element_Name in (' + #cols + ')
) p '
execute(#query);
Demo
By the way y don't u use PIVOT .Using PIVOT the same result can be achieved
Select [Parmitha],[Anggun],[Chandra],[BagusofTerror]
FROM
(
Select value,element_name from Sample
)src
pivot
(
max(value)
for Element_Name in ([Parmitha],[Anggun],[Chandra],[BagusofTerror])
)pvt

Resources