T sql pivot table selecting for IN - sql-server

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

Related

SQL Server Pivot single column values by multiple columns

CREATE TABLE TEMP (
DATE DATETIME
,category VARCHAR(3)
,amount MONEY
,NAMES VARCHAR(5)
)
INSERT INTO TEMP
VALUES (
'1/1/2012'
,'ABC'
,1000.00
,'john'
)
INSERT INTO TEMP
VALUES (
'2/1/2012'
,'DEF'
,500.00
,'amy'
)
INSERT INTO TEMP
VALUES (
'2/1/2012'
,'GHI'
,800.00
,'blue'
)
INSERT INTO TEMP
VALUES (
'2/10/2012'
,'DEF'
,700.00
,'ivy'
)
INSERT INTO TEMP
VALUES (
'3/1/2012'
,'ABC'
,1100.00
,'mark'
)
DECLARE #cols1 AS NVARCHAR(MAX)
,#cols2 AS NVARCHAR(MAX)
,#query AS NVARCHAR(MAX);
SET #cols1 = STUFF((
SELECT DISTINCT ',' + QUOTENAME(c.category)
FROM TEMP c
FOR XML PATH('')
,TYPE
).value('.', 'NVARCHAR(MAX)'), 1, 1, '')
SET #cols2 = STUFF((
SELECT DISTINCT ',' + QUOTENAME(c.NAMES)
FROM TEMP c
FOR XML PATH('')
,TYPE
).value('.', 'NVARCHAR(MAX)'), 1, 1, '')
--select #cols
SET #query = 'SELECT date, ' + #cols1 + #cols2 + ' from
(
select date
, amount
, category
, names
from temp
) x
pivot
(
max(amount)
for category in (' + #cols1 + ')
) p
pivot
(
max(amount)
for names in (' + #cols2 + ')
) p
'
EXEC (#query)
Drop table temp
Below is the result I'm trying to get but I get an error Invalid column name 'amount'
ABC DEF GHI John Amy Blue Ivy Mark
1/1/2012 1000 NULL NULL 1000 NULL NULL NULL NULL
2/1/2012 NULL 500 NULL NULL 500 NULL NULL NULL
2/1/2012 NULL NULL 800 NULL NULL 800 NULL NULL
2/10/2012 NULL 700 NULL NULL NULL NULL 700 NULL
3/1/2012 1100 NULL NULL NULL NULL NULL NULL 1100
You can try the below query.
CREATE TABLE TEMP (
DATE DATETIME
,category VARCHAR(3)
,amount MONEY
,NAMES VARCHAR(5)
)
INSERT INTO TEMP
VALUES (
'1/1/2012'
,'ABC'
,1000.00
,'john'
)
INSERT INTO TEMP
VALUES (
'2/1/2012'
,'DEF'
,500.00
,'amy'
)
INSERT INTO TEMP
VALUES (
'2/1/2012'
,'GHI'
,800.00
,'blue'
)
INSERT INTO TEMP
VALUES (
'2/10/2012'
,'DEF'
,700.00
,'ivy'
)
INSERT INTO TEMP
VALUES (
'3/1/2012'
,'ABC'
,1100.00
,'mark'
)
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX);
SET #cols = STUFF((SELECT distinct ',' + QUOTENAME(c.category)
FROM temp c
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT date, ' + #cols + ' from
(
select date
, amount
, category
from temp
) x
pivot
(
max(amount)
for category in (' + #cols + ')
) p '
execute(#query)
You can't use pivot like that, you need to pivot the data separately.
A quick way to get what you want would be:
WITH Table1 AS
(
SELECT date, [ABC],[DEF],[GHI]
from
(
select date
, amount
, category
, names
from temp
) AS x
pivot
(
MAX(Amount)
for category in ([ABC],[DEF],[GHI])
) AS A
)
,Table2 AS
(
SELECT date, [amy],[blue],[ivy],[john],[mark]
from
(
select date
, amount
, category
, names
from temp
) AS x
pivot
(
max(amount)
for names in ([amy],[blue],[ivy],[john],[mark])
) AS B
)
SELECT *
FROM Table1 A
INNER JOIN Table2 B on A.date = B.date;
Hope you got your result from this query.
CREATE TABLE #TEMP (DATE DATETIME,category VARCHAR(3),amount MONEY,NAMES VARCHAR(5))
INSERT INTO #TEMP VALUES ('3/1/2012','ABC',1100.00,'mark')
INSERT INTO #TEMP VALUES ('1/1/2012','ABC',1000.00,'john')
INSERT INTO #TEMP VALUES ('2/10/2012','DEF',700.00,'ivy')
INSERT INTO #TEMP VALUES ('2/1/2012','DEF',500.00,'amy')
INSERT INTO #TEMP VALUES ('2/1/2012','GHI',800.00,'blue')
select * into #Category from (-----CREATE PIVOT BASED ON CATEGORY FROM #TEMP TABLE AND INSERT DATA INTO #CATEGORY TABLE
select * from #TEMP
) as t1
pivot (sum(amount) for Category IN ([ABC],[DEF],[GHI])) AS CategoryAmount
select * into #Names from (-----CREATE PIVOT BASED ON NAMES FROM #TEMP TABLE AND INSERT DATA INTO #Names TABLE
select * from #TEMP
) as t1
pivot (sum(amount) for names IN ([amy],[blue],[ivy],[john],[mark])) AS CategoryAmount
--HERE IS YOUR FINAL QUERY WHERE YOU GOT YOUR RESULT AS PER YOUR REQUIREMENT
select c.DATE,SUM(c.ABC) ABC,SUM(c.DEF) DEF,SUM(c.GHI) GHI,SUM(n.John) JOHN,SUM(n.Amy) AMY,SUM(n.Blue) BLUE,SUM(n.Ivy) IVY,SUM(n.Mark) MARK from #Category C
inner join #Names n on c.DATE = n.DATE
GROUP BY C.DATE
drop table #TEMP,#Category,#Names

Created following query, Use 2 pivot for income and profit,But want order like 1 st column of profit then 1 st column of income

PIVOT Query:
Declare #cols nvarchar(max)
SELECT #cols= COALESCE (#cols+',['+shipmentmonth+' Profit]','['+shipmentmonth+' Profit]') from (select distinct shipmentmonth from MargaritaSales where ShipYearMonth >='201601' ) P
Declare #cols1 nvarchar(max)
SELECT #cols1= COALESCE (#cols1+',['+shipmentmonth+' Income]','['+shipmentmonth+' Income]') from (select distinct shipmentmonth from MargaritaSales where ShipYearMonth >='201601' ) P1
--Declare #cols nvarchar(max)
--SELECT #cols= COALESCE (#cols+',['+shipmentmonth+' Profit]'+'['+shipmentmonth+' Income]','['+shipmentmonth+' Profit]'+'['+shipmentmonth+' Income]') from (select distinct shipmentmonth from MargaritaSales where ShipYearMonth >='201601' ) P
--select #cols
DECLARE #query NVARCHAR(MAX)
SET #query =
'SELECT *
FROM ( SELECT T.buyer,T.buyerid, T.shipmentmonth,T.shipmentmonth+
''Income'' as shipmentmonth1,
(t.PROFIT +t.USDServiceIncome -t.USDServiceExpense) as Profit1,
( t.Income+t.OfficeIncome+t.USDServiceIncome) as Income1
FROM MargaritaSales T where T.ShipYearMonth >=''201601'') up PIVOT
(sum(PROFIT1)
FOR shipmentmonth IN ('+ #cols +')) AS pvt1
PIVOT (sum(Income1)
FOR shipmentmonth1 IN (+ #cols1 + ')) AS pvt2'
EXEC SP_EXECUTESQL #query
it is easier to use CASE STATEMENT for such case rather than PIVOT
this is how it is looks like. You need to convert to Dynamic Query as per what you did with PIVOTing
SELECT T.buyer, T.buyerid,
SUM(CASE WHEN ShipYearMonth = 201601 THEN t.PROFIT + t.USDServiceIncome -t.USDServiceExpense END) as Profit1,
SUM(CASE WHEN ShipYearMonth = 201601 THEN t.Income + t.OfficeIncome + t.USDServiceIncome) as Income1,
SUM(CASE WHEN ShipYearMonth = 201602 THEN t.PROFIT + t.USDServiceIncome -t.USDServiceExpense END) as Profit2,
SUM(CASE WHEN ShipYearMonth = 201602 THEN t.Income + t.OfficeIncome + t.USDServiceIncome) as Income2
FROM MargaritaSales T
WHERE T.ShipYearMonth >= 201601
GROUP BY T.buyer, T.buyerid

Pivot with Group by on SQL

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

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

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