Prefixed Columns are not allowed in PIVOT Operator - sql

My Query as below :
select * from
(
SELECT ShoperCompCode, Name, Qty, Value, Tb, ASP, UPT, AST, CTS, class2cd, CashSaleQty FROM MBDSR
)A
PIVOT (AVG(CashSaleQty) FOR class2cd IN ("")) AS PVT
Tables as below :
ShoperCompCode Name Qty Value Tb ASP UPT AST CTS class2cd CashSaleQty
MB1 TEST 35 77064 6 2201.83 5.83 12844 0.44 Jeans 1
MB2 TEST2 5 11095 2 2219 2.5 5547.5 0.06 T-shirt 2
MB3 TEST3 0 0 0 0 0 0 0 Jeans 3
Now, i don't know the class2cd value wheather it will be "Jeans" or "T-shirt"
I.e (Class2Cd data is not static, it will be dynamic)..

Problem has been resolved check my updated code.
DECLARE #cols AS NVARCHAR(MAX),#query AS NVARCHAR(MAX)
Select #cols = STUFF((SELECT DISTINCT ',' + QUOTENAME(Class2Cd)
from MBDSR
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT * from
(
SELECT ShoperCompCode, Name, Qty, Value, Tb, ASP, UPT, AST, CTS, class2cd, CashSaleQty FROM MBDSR
) x
pivot
(
AVG(CashSaleQty) FOR class2cd IN (' + #cols + ')
) p '
execute(#query);

Related

Pivot Sql with no aggregate

I learned I can't pivot text without aggregation max() & min().
I am trying to figure out a workaround but the answers to similar questions are sailing over my head. would anyone have tips to workaround that?
data table:
pax
codex
mis
dog1
hair
10
dog1
face
10
dog1
eye
5
dog1
smell
7
dog1
yellow
7
dog1
green
8
dog1
blue
9
dog1
tan
10
desired output:
pax
10
10
5
7
7
8
9
10
dog1
hair
face
eye
smell
yellow
green
blue
tan
actual outcome:
pax
10
5
7
8
9
dog1
hair
eye
smell
green
blue
I used this code:
DECLARE #cols AS NVARCHAR(MAX)='';
DECLARE #query AS NVARCHAR(MAX)='';
SELECT #cols = #cols + QUOTENAME(mis) + ',' FROM (select distinct mis from #dd) as tmp
select #cols = substring(#cols, 0, len(#cols)) --trim "," at end
set #query =
'SELECT * from
(
select pax,codex,mis from #dd
) src
pivot
(
max(codex) for mis in (' + #cols + ')
) piv'
execute(#query)
Try this
Select
pax,
concat(mis, '-', rn) as mis_new,
codex
from (
Select
pax,
mis,
row_number() over (partition by pax, mis
order by mis ) rn
from table
) t
pivot (
max(codex) for (
mis_new in ('10-1','10-2', '5-1','7-1','7-2','8-1','9-1','10-3')
) pvt
It looks like standard conditional aggregation over a row-number would serve better:
DECLARE #cols AS NVARCHAR(MAX) =
(
SELECT CONCAT(',MIN(CASE WHEN mis = ', QUOTENAME(mis, ''''), ' AND rn = ', rn, ' THEN codex END) ', QUOTENAME(mis))
FROM (
SELECT *,
ROW_NUMBER() OVER (PARTITION BY pax ORDER BY mis) rn
FROM dd
) as tmp
GROUP BY mis, rn
FOR XML PATH(''), TYPE
).value('text()[1]','nvarchar(max)');
DECLARE #query AS NVARCHAR(MAX) = '
SELECT
pax' + #cols + '
FROM (
SELECT *,
ROW_NUMBER() OVER (PARTITION BY pax ORDER BY mis) rn
FROM dd
) dd
GROUP BY pax;
';
PRINT #query; --for testing
EXEC sp_executesql
#query;
db<>fiddle
Note the use of FOR XML to aggregate. Variable coalescing should not be used, due to unpredictability.

SQL Query rows need to be converted to columns dynamically

Please help me to solve my below query -
I have the following data in my table-
Agent Variable Chandigarh NewDelhi
ABC Leads 102.00 10
ABC TotalTime 10.52 1
ABC RPH 22.79 22
ABC TotalRev 239.70 23
XYZ Leads 14.00 14
XYZ TotalTime 1.52 1
XYZ RPH 21.64 21
XYZ TotalRev 32.90 32
I want the solution like this
Agent Chandigarh_Leads Chandigarh_TotalTime Chandigarh_RPH Chandigarh_RPH_TotalRev NewDelhi_Leads .......
ABC 102.00 10.52 22.79 239.70 10 .......
XYZ 14 1.52 21.64 32.90 14 ............
FYI, I can have more states in columns, it has no limits it may be 10 or 20 or 5 etc. So i need result dynamic query. Please help me, is it possible without static query?
Dynamic SQL + pivoting:
DECLARE #sql nvarchar(max),
#columns nvarchar(max),
#col_to_cast nvarchar(max),
#col_unpvt nvarchar(max)
--This will give:
--,[Chandigarh_Leads],[Chandigarh_RPH]....[NewDelhi_TotalRev],[NewDelhi_TotalTime]
SELECT #columns = COALESCE(#columns,'')+',['+name+'_'+Variable +']'
FROM (
SELECT DISTINCT Variable
FROM #yourtable) v
CROSS JOIN (
SELECT name
FROM sys.columns
WHERE object_id = OBJECT_ID(N'#yourtable')
AND name not in ('Agent', 'Variable')
) c
ORDER BY c.name, v.Variable
--As columns while unpivoting must be same type we need to cast them in same datattype:
--This will give
--,CAST([Chandigarh] as float) as [Chandigarh],CAST([NewDelhi] as float) as [NewDelhi]
SELECT #col_to_cast = COALESCE(#col_to_cast,'')+',CAST(' + QUOTENAME(name)+ ' as float) as '+ QUOTENAME(name)
#col_unpvt = COALESCE(#col_unpvt,'') + ','+ QUOTENAME(name)
FROM sys.columns
WHERE object_id = OBJECT_ID(N'#yourtable')
AND name not in ('Agent', 'Variable')
SELECT #sql = N'
SELECT *
FROM (
SELECT Agent,
[Columns]+''_''+Variable as ColName,
[Values] as ColVal
FROM (
SELECT Agent,
Variable'+#col_to_cast+'
FROM #yourtable
) p
UNPIVOT (
[Values] FOR [Columns] IN ('+STUFF(#col_unpvt,1,1,'')+')
) unpvt
) t
PIVOT (
MAX(ColVal) FOR ColName IN ('+STUFF(#columns,1,1,'')+')
) pvt'
EXEC sp_executesql #sql
Output:
Agent Chandigarh_Leads Chandigarh_RPH Chandigarh_TotalRev Chandigarh_TotalTime NewDelhi_Leads NewDelhi_RPH NewDelhi_TotalRev NewDelhi_TotalTime
ABC 102 22,79 239,7 10,52 10 22 23 1
XYZ 14 21,64 32,9 1,52 14 21 32 1

SQL Server 2008 CrossTab equivalent

Afternoon Guys n Girls.
Using SQL SERVER 2008.
I have a table called userModList. Its contains fields, "USERID"(int), "ModuleID"(int), and "Passed"(bin).
example data;
USERID ModuleID Passed
134 12 1
134 10 0
134 18 1
What i would like to display is:
USERID (moduleNum12) (ModuleNum10) (ModuleNum18)
134 1 0 1
Now In MS access all you would do is create a cross query, so User ID becomes the row, Module numbers become the Columns and Passed is the values (binary 1 or 0).
I would like to do this server Side in a Stored Procedure, but I have never Attempted cross tabbing data.
Also The moduleID is dynamic meaning there may be 3 modules for a user or 17. So it needs to be dynamic, not sure if this makes a big difference?
Anyway some help on this would be great, ill try and provide some sample code Of what I will try, But as it stands I'm stuck as to where to start.
many thanks guys!
There are a few different ways that you can do this in SQL Server you can use the PIVOT function:
select userid,
[12] moduleNum12,
[10] moduleNum10,
[18] moduleNum18
from
(
select userid, moduleid, cast(passed as int) passed
from yourtable
) d
pivot
(
max(passed)
for moduleId in ([12], [10], [18])
) piv;
See Demo
Or you can use an aggregate function with a CASE expression:
select userid,
max(case when moduleid = 12 then cast(passed as int) end) moduleNum12,
max(case when moduleid = 10 then cast(passed as int) end) moduleNum10,
max(case when moduleid = 18 then cast(passed as int) end) moduleNum18
from yourtable
group by userid;
See Demo.
The above work great if the values are known nut if you have unknown values, then you will need to use dynamic SQL:
DECLARE #cols AS NVARCHAR(MAX),
#colsAlias AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT distinct ',' + QUOTENAME(ModuleID)
from yourtable
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
select #colsAlias = STUFF((SELECT distinct ', ' + QUOTENAME(ModuleID) +' as moduleNum'+cast(ModuleID as varchar(10))
from yourtable
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT userid,' + #colsAlias + '
from
(
select userid, moduleid, cast(passed as int) passed
from yourtable
) d
pivot
(
max(passed)
for moduleid in (' + #cols + ')
) p '
execute(#query)
See Demo

pivoting rows to columns in tsql

I have the following table with the following sample data
ID Language Question SubQuestion SubSubQuestion TotalCount TotalPercent
3 E 9 0 1 88527 73%
3 E 9 0 2 19684 16%
3 E 9 0 3 12960 11%
3 E 9 0 9 933 1%
I want all in one row like this
ID Language TotalCount901 TotalPercent901 TotalCount902 TotalPercent902 TotalCount903 TotalPercent903
3 E 88527 73% 19684 16% 12960 11%
I've tired using the pivot command, but it dosnt to work for me.
I made a few assumptions based on your column names, but it looks like you want to use something similar to this. This applies both an UNPIVOT and then a PIVOT to get the values in the columns you requested:
select *
from
(
select id,
language,
col + cast(QUESTION as varchar(10))
+cast(subquestion as varchar(10))
+cast(SubSubQuestion as varchar(10)) col,
value
from
(
select id, language,
cast(TotalCount as varchar(10)) TotalCount,
totalPercent,
question, subquestion, SubSubQuestion
from yourtable
) usrc
unpivot
(
value
for col in (totalcount, totalpercent)
) un
) srcpiv
pivot
(
max(value)
for col in ([TotalCount901], [totalPercent901],
[TotalCount902], [totalPercent902],
[TotalCount903], [totalPercent903],
[TotalCount909], [totalPercent909])
) p
See SQL Fiddle with Demo
Note: when performing the UNPIVOT the columns need to be of the same datatype. If they are not, then you will need to convert/cast to get the datatypes the same.
If you have an unknown number of values to transform, you can use dynamic sql:
DECLARE #query AS NVARCHAR(MAX),
#colsPivot as NVARCHAR(MAX)
select #colsPivot
= STUFF((SELECT ','
+ QUOTENAME(c.name +
cast(QUESTION as varchar(10))
+cast(subquestion as varchar(10))
+cast(SubSubQuestion as varchar(10)))
from yourtable t
cross apply sys.columns as C
where C.object_id = object_id('yourtable') and
C.name in ('TotalCount', 'TotalPercent')
group by c.name, t.question, t.subquestion, t.subsubquestion
order by t.SubSubQuestion
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'select *
from
(
select id,
language,
col + cast(QUESTION as varchar(10))
+cast(subquestion as varchar(10))
+cast(SubSubQuestion as varchar(10)) col,
value
from
(
select id, language,
cast(TotalCount as varchar(10)) TotalCount,
totalPercent,
question, subquestion, SubSubQuestion
from yourtable
) usrc
unpivot
(
value
for col in (totalcount, totalpercent)
) un
) srcpiv
pivot
(
max(value)
for col in (' + #colsPivot + ')
) p '
execute(#query)
See SQL Fiddle with Demo

display rows as column

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