Can I use a WHILE loop inside a SQL SELECT Query - sql

I need to create a formatted text (CSV) output with an even number of columns from a SQL query of two tables that do not have the same number of elements. I can't seem to pad the data to the required number of columns.
Sample Data
table Students(id, name)
values
(1, Alex),
(2, Bob),
(3, Charlie),
(4, David)
table Hobbies (studentId, hobby)
values
(2,'skating')
(2,'sailing')
(3,'reading')
(4,'video games')
(4,'paintball')
(4,'nascar')
(4,'baseball')
Desired Output
[ID][OutputString]
[0][Student,Hobby1,Hobby2,Hobby3,Hobby4]
[1][Alex,,,,]
[2][Bob,skating,sailing,]
[3][Charlie,reading,,,]
[4][David,video games,paintball,nascar,baseball]
Broken PseudoCode
DECLARE #maxHobbies INT = 4;
DECLARE #hobbyCount INT = 1;
DECLARE headerString varchar(max) = 'Student';
WHILE #hobbyCount <= #maxHobbies
BEGIN
set #headerString = #headerString + ',Hobby' + #hobbyCount
#hobbyCount = #hobbyCount + 1
END
DECLARE #outputString varchar(max)
SET #outputString = concat(#headerSting, char(13)) +
SELECT 0 AS ID, #headerString AS OutputString
UNION
SELECT
id,
name + (WHILE #hobbyCount <= #maxHobbies BEGIN
(CASE
WHEN EXISTS SELECT hobby FROM Hobbies where studentId = Students.id
THEN ',' + SELECT hobby FROM Hobbies where studentId = Students.id
ELSE ','
END)
END)
FROM Students

You want up to 4 hobbies. You can do this with conditional aggregation:
select s.id,
(s.name + ',' +
max(case when seqnum = 1 then h.hobby else '' end) + ',' +
max(case when seqnum = 2 then h.hobby else '' end) + ',' +
max(case when seqnum = 3 then h.hobby else '' end) + ',' +
max(case when seqnum = 4 then h.hobby else '' end)
) as outputstring
from students s left join
(select h.*,
row_number() over (partition by h.studentid order by (select null)) as seqnum
from hobbies h
) h
on h.studentid = s.id
group by s.id, s.name;

Related

Add percentage on every columns on pivot table

******Here is below query for your knowledge how to add percentge columns on every pivot columns let you give the answer 1
I've created a SQL pivot and want to add a further calculated percentage column based on the aggregated figures within and I cannot figure out how to make this happen.****
DELETE TOP(100) PERCENT FROM PlusRS.rpt.RepairLevel
-- STEP NO. 2
INSERT INTO PlusRS.rpt.RepairLevel (ProgramID, PartNo, SerialNo, InvoiceFamily, RepairLevel)
SELECT WOH.ProgramID
, WOH.PartNo
, WOH.SerialNo
, PNA.Value AS InvoiceFamily
, CASE WOH.RepairTypeID WHEN 42 THEN '1'
WHEN 71 THEN '3'
ELSE MAX(PLVL.Value)
END AS RepairLevel
FROM pls.WOHeader WOH
INNER JOIN pls.WOStationHistory WSH ON WOH.ID = WSH.WOHeaderID
INNER JOIN pls.CodeRepairType CRT ON CRT.ID = WOH.RepairTypeID
INNER JOIN pls.WOLine WOL ON WOL.WOHeaderID = WOH.ID AND WOL.StatusID = 14
LEFT JOIN pls.PartNoAttribute PNA ON PNA.AttributeID = 354 AND PNA.ProgramID = WOH.ProgramID AND PNA.PartNo = WOH.PartNo
LEFT JOIN pls.PartNoAttribute PLVL ON PLVL.AttributeID = 149 AND PNA.ProgramID = WOH.ProgramID AND PLVL.PartNo = WOL.ComponentPartNo
WHERE WSH.IsPass = 1 AND WSH.WorkStationID = 2 AND WOH.StatusID != 3
AND woh.ProgramID = '10001' and CONVERT(Date, WSH.lastactivitydate) >= '2022.04.11 ' AND CONVERT(Date, WSH.lastactivitydate) <= '2022.06.15'
GROUP BY WOH.ProgramID
, WOH.PartNo
, WOH.SerialNo
, PNA.Value
, WOH.RepairTypeId
UPDATE PlusRS.rpt.RepairLevel SET BCRatio = CASE WHEN RepairLevel = '0' THEN 9
WHEN RepairLevel = '1' THEN 0
WHEN RepairLevel = '2' THEN 53
WHEN RepairLevel = '2.5' THEN 0
WHEN RepairLevel = '3' THEN 38
WHEN RepairLevel = 'O' THEN 0
END
Declare #sqlquery nvarchar(max),
#column nvarchar(max);
SELECT #column = COALESCE(#column + ',', '') + QUOTENAME(InvoiceFamily)
FROM
(
SELECT Distinct InvoiceFamily
FROM PlusRS.rpt.RepairLevel
) AS PIVOT_COLUMNS
DECLARE #ColumnForSum AS NVARCHAR(MAX)
SELECT #ColumnForSum =REPLACE(#column,',','+')
SELECT #ColumnForSum =REPLACE(#ColumnForSum,'[','ISNULL([')
SELECT #ColumnForSum =REPLACE(#ColumnForSum,']','],0)')
SET #sqlquery =
N'select * into #TempBag from
(
SELECT SerialNo as Qty
, InvoiceFamily
, RepairLevel
, BCRatio
FROM
PlusRS.rpt.RepairLevel
)as t
pivot(
count(qty)
for InvoiceFamily In('+#column+')
)As Pvt_table
ORDER BY RepairLevel
select t.*, SUM('+#ColumnForSum+') Total from #TempBag t
GROUP BY RepairLevel,BCRatio,'+#column+'
Drop Table #TempBag'
EXEC sp_executesql #sqlquery**

SQL pivot single to multiple column and multiple row

Can somebody help me with SQL using pivot?
I asked before this using numbers but not now im using it in a string format
For example I have a list of Names shown below with 1 column:
and I want the result to become this. the will limit 10 column only
use row_number() to generate a running sequence, and then, use modulus % to get the column and divide by 10 to get the row. Use PIVOT() to get the required result
select *
from
(
select [Names],
[row] = row_number() over (order by [Names]) / 10 + 1,
[col] = (row_number() over (order by [Names]) - 1) % 10 + 1
from yourtable
) d
pivot
(
max([Names])
for col in ([1], [2],[3],[4],[5],[6],[7],[8],[9],[10])
) p
I would just use conditional aggregation:
select max(case when seqnum % 10 = 0 then name end) as name_0,
max(case when seqnum % 10 = 1 then name end) as name_1,
max(case when seqnum % 10 = 2 then name end) as name_2,
max(case when seqnum % 10 = 3 then name end) as name_3,
max(case when seqnum % 10 = 4 then name end) as name_4,
max(case when seqnum % 10 = 5 then name end) as name_5,
max(case when seqnum % 10 = 6 then name end) as name_6,
max(case when seqnum % 10 = 7 then name end) as name_7,
max(case when seqnum % 10 = 8 then name end) as name_8,
max(case when seqnum % 10 = 9 then name end) as name_9
from (select t.*,
row_number() over (order by (select null)) - 1 as seqnum
from t
) t
group by floor(seqnum / 10);
Note: The ordering of the names in the result set is not guaranteed. Each name will appear in one position. If the ordering matters, then you need an additional column that specifies the ordering (and you can use that in the group by.
This code solves your question using dynamic pivot and without sorting the data with select null
declare #groups varchar(max) set #groups = (select count(0)/2 from Mytable )
declare #columns varchar(max) set #columns = ''
select #columns = coalesce(#columns + '[' + cast(col as varchar(MAX)) + '],', '')
FROM (
select col from (
select (row_number() over (order by (SELECT NULL)) - 1) % (#groups) + 1 as col
from Mytable group by Names
) t
group by col
) m
set #columns = left(#columns,LEN(#columns)-1)
DECLARE #SQLString nvarchar(max);
set #SQLString = '
select * from
(
select Names, row/'+#groups+' +1 as row , col from (
select [Names],
[row] = row_number() over (order by (SELECT NULL))+1 / '+#groups+' -1,
[col] = (row_number() over (order by (SELECT NULL)) - 1) % '+#groups+' + 1
from Mytable
) x
) m
PIVOT
( MAX(Names)
FOR col in (' + #columns + ')
) AS PVT'
EXECUTE sp_executesql #SQLString

convert Rows to Columns in SQL with same ID

Folks,
I have a table with data as below.
enter image description here
Please advise sql logic to be applied to achieve this output.
One method is to use conditional aggregation:
select travelid,
max(case when seqnum = 1 then earn end) as earn,
max(case when seqnum = 1 then burn end) as burn,
max(case when seqnum = 2 then earn end) as earnA,
max(case when seqnum = 2 then burn end) as burnB
from (select t.*, row_number() over (partition by travelid order by travelid) as seqnum
from t
) t
group by travelid
SQL Server Dynamic version :
--TEST DATA
CREATE TABLE #TestTable
([TravelID] int, [SitelD] int, [Flagi] int, [FIag2] int)
;
INSERT INTO #TestTable
([TravelID], [SitelD], [Flagi], [FIag2])
VALUES
(1001, 1, 1, 0),(1001, 1, 0, 1),(1001, 1, 3, 4),
(1002, 1, 1, 0),(1002, 2, 0, 1),(1002, 2, 3, 4)
;
--STEP 1 rank data
SELECT * into #rank_table from (
select *
,ROW_NUMBER() OVER (PARTITION BY [TravelID],[SitelD] order by [SitelD]) [rank]
from (
select * from #TestTable
) T100
)T;
--STEP 2 Group by row_count
SELECT * into #group_table from (
select [TravelID],[SitelD] ,count(1) [count]
from #TestTable T
group by [TravelID],[SitelD]
)T;
--Use Exec
DECLARE #select_sql AS NVARCHAR(MAX) = ' select T.[TravelID], T.[SitelD] ',
#join_sql AS NVARCHAR(MAX) = ' from #group_table T ',
#max_count INT = (SELECT max([count]) FROM #group_table),
#temp_string NVARCHAR(5),
#temp_string_addone NVARCHAR(5)
;
DECLARE #index int = 0 ;
WHILE #index < #max_count
BEGIN
sELECT #temp_string = Convert(nvarchar(10),#index);
sELECT #temp_string_addone = Convert(nvarchar(10),#index+1);
select #select_sql = #select_sql + ' , T'+#temp_string_addone+'.[Flagi] as Flag'+Convert(nvarchar(10),2*#index+1)+' '
+ ' , T'+#temp_string_addone+'.[FIag2] as Flag'+Convert(nvarchar(10),2*#index+2)+' ';
select #join_sql = #join_sql + 'left join #rank_table T'+#temp_string_addone+' on ' + ' T.[TravelID] = T'+#temp_string_addone+'.[TravelID] and '
+ ' T.[SitelD] = T'+#temp_string_addone+'.[SitelD] and '
+ 'T'+#temp_string_addone+'.[rank] = '+#temp_string_addone+' ';
SET #index = #index + 1;
END;
EXEC (#select_sql
+ #join_sql
+' order by [TravelID],[SitelD] ; ')
;
DEMO : convert Rows to Columns in SQL with same ID, Sql Server - rextester
with CTE as(
select
*
,ROW_NUMBER() OVER (PARTITION BY [TravelID],[SitelD] order by [SitelD]) [rk]
from [Table]
)
select distinct a.[TravelID], a.[SitelD], a.[Flagi] as Flag1, a.[FIag2] as Flag1, b.[Flagi] as Flag3, b.[FIag2] as Flag4
from (select * from CTE where [rk] = 1) a
left join (select * from CTE where [rk] = 2) b on a.[TravelID] = b.[TravelID] and a.[SitelD] = + b.[SitelD]

How can I query row data as columns?

I'm sure I'm missing something here.
I have a dataset like this:
FK RowNumber Value Type Status
1 1 aaaaa A New
1 2 bbbbb B Good
1 3 ccccc A Bad
1 4 ddddd C Good
1 5 eeeee B Good
2 1 fffff C Bad
2 2 ggggg A New
2 3 hhhhh C Bad
3 1 iiiii A Good
3 2 jjjjj A Good
I'd like to query the top 3 results and Pivot them as columns, so the end result set looks like this:
FK Value1 Type1 Status1 Value2 Type2 Status2 Value3 Type3 Status3
1 aaaaa A New bbbbb B Good ccccc A Bad
2 fffff C Bad ggggg A New hhhhh C Bad
3 iiiii A Good jjjjj A Good
How can I accomplish this in SQL Server 2005?
I have been attempting this using PIVOT, but I am still very unfamiliar with that keyword and cannot get it to work the way I want.
SELECT * --Id, [1], [2], [3]
FROM
(
SELECT Id, Value, Type, Status
, ROW_NUMBER() OVER (PARTITION BY Id ORDER Status, Type) as [RowNumber]
FROM MyTable
) as T
PIVOT
(
-- I know this section doesn't work. I'm still trying to figure out PIVOT
MAX(T.Value) FOR RowNumber IN ([1], [2], [3]),
MAX(T.Type) FOR RowNumber IN ([1], [2], [3]),
MAX(T.Status) FOR RowNumber IN ([1], [2], [3])
) AS PivotTable;
My actual data set is a bit more complex than this, and I need the top 10 records, not the top 3, so I don't want to simply do CASE WHEN RowNumber = X THEN... for each one.
Update
I tested all the answers below, and found most of them seem about the same with no apparent performance difference in smaller data sets (around 3k records), however there was a slight difference when running the queries against larger data sets.
Here are the results of my tests using 80,000 records and querying for 5 columns in the top 10 rows, so my end result set was 50 columns + the Id column. I'd suggest you test them on your own to decide which one works best for you and your environment.
bluefoot's answer of unpivoting and re-pivoting the data averaged the fastest at about 12 seconds. I also liked this answer because I found it easiest to read and maintain.
Aaron's answer and koderoid's answer both suggest using a MAX(CASE WHEN RowNumber = X THEN ...), and was close behind averaging at around 13 seconds.
Rodney's answer of using multiple PIVOT statements averaged around 16 seconds, although it might be faster with fewer PIVOT statements (my tests had 5).
And the first half of Aaron's answer that suggested using a CTE and OUTER APPLY was the slowest. I don't know how long it would take to run because I cancelled it after 2 minutes, and that was with around 3k records, 3 rows, and 3 columns instead of 80k records, 10 rows, and 5 columns.
You can do an UNPIVOT and then a PIVOT of the data. this can be done either statically or dynamically:
Static Version:
select *
from
(
select fk, col + cast(rownumber as varchar(1)) new_col,
val
from
(
select fk, rownumber, value, cast(type as varchar(10)) type,
status
from yourtable
) x
unpivot
(
val
for col in (value, type, status)
) u
) x1
pivot
(
max(val)
for new_col in
([value1], [type1], [status1],
[value2], [type2], [status2],
[value3], [type3])
) p
see SQL Fiddle with demo
Dynamic Version, this will get the list of columns to unpivot and then to pivot at run-time:
DECLARE #colsUnpivot AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX),
#colsPivot as NVARCHAR(MAX)
select #colsUnpivot = stuff((select ','+quotename(C.name)
from sys.columns as C
where C.object_id = object_id('yourtable') and
C.name not in ('fk', 'rownumber')
for xml path('')), 1, 1, '')
select #colsPivot = STUFF((SELECT ','
+ quotename(c.name
+ cast(t.rownumber as varchar(10)))
from yourtable t
cross apply
sys.columns as C
where C.object_id = object_id('yourtable') and
C.name not in ('fk', 'rownumber')
group by c.name, t.rownumber
order by t.rownumber
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query
= 'select *
from
(
select fk, col + cast(rownumber as varchar(10)) new_col,
val
from
(
select fk, rownumber, value, cast(type as varchar(10)) type,
status
from yourtable
) x
unpivot
(
val
for col in ('+ #colsunpivot +')
) u
) x1
pivot
(
max(val)
for new_col in
('+ #colspivot +')
) p'
exec(#query)
see SQL Fiddle with Demo
Both will generate the same results, however the dynamic is great if you do not know the number of columns ahead of time.
The Dynamic version is working under the assumption that the rownumber is already a part of the dataset.
You can try to do the pivot in three separate pivot statements. Please give this a try:
SELECT Id
,MAX(S1) [Status 1]
,MAX(T1) [Type1]
,MAX(V1) [Value1]
--, Add other columns
FROM
(
SELECT Id, Value , Type, Status
, 'S' + CAST(ROW_NUMBER() OVER (PARTITION BY Id ORDER BY Status, Type) AS VARCHAR(10)) [Status_RowNumber]
, 'T' + CAST(ROW_NUMBER() OVER (PARTITION BY Id ORDER BY Status, Type) AS VARCHAR(10)) [Type_RowNumber]
, 'V' + CAST(ROW_NUMBER() OVER (PARTITION BY Id ORDER BY Status, Type) AS VARCHAR(10)) [Value_RowNumber]
FROM MyTable
) as T
PIVOT
(
MAX(Status) FOR Status_RowNumber IN ([S1], [S2], [S3],[S4],[S5],[S6],[S7],[S8],[S9],[S10])
)AS StatusPivot
PIVOT(
MAX(Type) FOR Type_RowNumber IN ([T1], [T2], [T3],[T4],[T5],[T6],[T7],[T8],[T9],[T10])
)AS Type_Pivot
PIVOT(
MAX(Value) FOR Value_RowNumber IN ([V1], [V2], [V3],[V4],[V5],[V6],[V7],[V8],[V9],[V10])
)AS Value_Pivot
GROUP BY Id
I don't know the full scope of the criteria for selecting the top ten records, but this produces and output that may get you closer to your answer.
SQL Fiddle Example
Rodney's muli-pivot is clever, that's for sure. Here are two other alternatives that are of course less appealing when you get into the 10X vs. 3X area.
;WITH a AS
(
SELECT Id, Value, Type, Status,
n = ROW_NUMBER() OVER (PARTITION BY Id ORDER BY [Status], [Type])
FROM dbo.MyTable
)
SELECT a.Id,
Value1 = a.Value, Type1 = a.[Type], Status1 = a.[Status],
Value2 = b.Value, Type2 = b.[Type], Status2 = b.[Status],
Value3 = c.Value, Type3 = c.[Type], Status3 = c.[Status]
FROM a
OUTER APPLY (SELECT * FROM a AS T2 WHERE n = a.n + 1 AND id = a.id) AS b
OUTER APPLY (SELECT * FROM a AS T2 WHERE n = b.n + 1 AND id = b.id) AS c
WHERE a.n = 1
ORDER BY a.Id;
-- or --
;WITH a AS
(
SELECT Id, Value, [Type], [Status],
n = ROW_NUMBER() OVER (PARTITION BY Id ORDER BY [Status], [Type])
FROM dbo.MyTable
)
SELECT Id,
Value1 = MAX(CASE WHEN n = 1 THEN Value END),
Type1 = MAX(CASE WHEN n = 1 THEN [Type] END),
Status1 = MAX(CASE WHEN n = 1 THEN [Status] END),
Value2 = MAX(CASE WHEN n = 2 THEN Value END),
Type2 = MAX(CASE WHEN n = 2 THEN [Type] END),
Status2 = MAX(CASE WHEN n = 2 THEN [Status] END),
Value3 = MAX(CASE WHEN n = 3 THEN Value END),
Type3 = MAX(CASE WHEN n = 3 THEN [Type] END),
Status3 = MAX(CASE WHEN n = 3 THEN [Status] END)
FROM a
GROUP BY Id
ORDER BY a.Id;
This might work for you, though it's not elegant.
select aa.FK_Id
, isnull(max(aa.Value1), '') as Value1
, isnull(max(aa.Type1), '') as Type1
, isnull(max(aa.Status1), '') as Status1
, isnull(max(aa.Value2), '') as Value2
, isnull(max(aa.Type2), '') as Type2
, isnull(max(aa.Status2), '') as Status2
, isnull(max(aa.Value3), '') as Value3
, isnull(max(aa.Type3), '') as Type3
, isnull(max(aa.Status3), '') as Status3
from
(
select FK_Id
, case when RowNumber = 1 then Value else null end as Value1
, case when RowNumber = 1 then [Type] else null end as Type1
, case when RowNumber = 1 then [Status] else null end as Status1
, case when RowNumber = 2 then Value else null end as Value2
, case when RowNumber = 2 then [Type] else null end as Type2
, case when RowNumber = 2 then [Status] else null end as Status2
, case when RowNumber = 3 then Value else null end as Value3
, case when RowNumber = 3 then [Type] else null end as Type3
, case when RowNumber = 3 then [Status] else null end as Status3
from Table1
) aa
group by aa.FK_Id
try something like this:
declare #rowCount int
set #rowCount = 10
declare #isNullClause varchar(4024)
set #isnullClause = ''
declare #caseClause varchar(4024)
set #caseClause = ''
declare #i int
set #i = 1
while(#i <= #rowCount) begin
set #isnullClause = #isNullClause +
' , max(aa.Value' + CAST(#i as varchar(3)) + ') as Value' + CAST(#i as varchar(3)) +
' , max(aa.Type' + CAST(#i as varchar(3)) + ') as Type' + CAST(#i as varchar(3)) +
' , max(aa.Status' + CAST(#i as varchar(3)) + ') as Status' + CAST(#i as varchar(3)) + ' ';
set #caseClause = #caseClause +
' , case when RowNumber = ' + CAST(#i as varchar(3)) + ' then Value else null end as Value' + CAST(#i as varchar(3)) +
' , case when RowNumber = ' + CAST(#i as varchar(3)) + ' then Type else null end as Type' + CAST(#i as varchar(3)) +
' , case when RowNumber = ' + CAST(#i as varchar(3)) + ' then Status else null end as Status' + CAST(#i as varchar(3)) + ' '
set #i = #i + 1;
end
declare #sql nvarchar(4000)
set #sql = 'select aa.FK_Id ' + #isnullClause + ' from ( select FK_Id '
+ #caseClause + ' from Table1) aa group by aa.FK_Id '
exec SP_EXECUTESQL #sql

Dynamic Multi-Column SQL

I have two tables with structures like this:
VelocityBase
Aisle | ItemId | ConfigId | InventSizeId | InventColorId | InventLocationId | DataAreaId | VelocityCategory
VelocitySalesCount
ItemId | ConfigId | InventSizeId | InventColorId | InventLocationId | DataAreaId | Sales
Every row in the Base table represents a SKU and the sum of the related SalesCount records' "Sales" fields determines the "Picks". This query works:
SELECT Aisle, COUNT(*) as '# SKUs',
SUM(Sales) as '# Picks',
SUM(CASE WHEN VelocityCategory = 'Hot' THEN 1 ELSE 0 END) as 'Hot SKUs',
SUM(CASE WHEN VelocityCategory = 'Hot' THEN SALES ELSE 0 END) as 'Hot Picks',
SUM(CASE WHEN VelocityCategory = 'Warm' THEN 1 ELSE 0 END) as 'Warm SKUs',
SUM(CASE WHEN VelocityCategory = 'Warm' THEN SALES ELSE 0 END) as 'Warm Picks',
SUM(CASE WHEN VelocityCategory = 'Cold' THEN 1 ELSE 0 END) as 'Cold SKUs',
SUM(CASE WHEN VelocityCategory = 'Cold' THEN SALES ELSE 0 END) as 'Cold Picks'
FROM [dbo].[VelocityBase] Base
LEFT OUTER JOIN [dbo].[VelocitySalesCount] SalesCount
ON Base.ItemId = SalesCount.ItemId
AND Base.ConfigId = SalesCount.ConfigId
AND Base.InventSizeId = SalesCount.InventSizeId
AND Base.InventColorId = SalesCount.InventColorId
AND Base.InventLocationId = SalesCount.InventLocationId
AND SalesCount.DataAreaId = Base.DataAreaId
GROUP BY Aisle
ORDER BY Aisle
However, the columns are hard coded. What I would like is that the "Hot", "Warm", "Cold", etc be generated based on what values are present in the database for this column. That way if a user added a row that had "Lukewarm" as the VelocityCategory, two new columns would appear with that data.
I'm not sure if something like SQL to generate SQL or maybe a PIVOT function would do the trick.
Thanks in advance!
EDIT:
I'm narrowing in. I've got the Sum of the Sales figures using this:
DECLARE #SQLStatement NVARCHAR(4000)
,#PivotValues NVARCHAR(4000);
SET #PivotValues = '';
SELECT #PivotValues = #PivotValues + ',' + QUOTENAME(VelocityCategory)
FROM
(
SELECT DISTINCT VelocityCategory
FROM dbo.VelocityBase
) src;
SET #PivotValues = SUBSTRING(#PivotValues,2,4000);
SELECT #SQLStatement =
'SELECT pvt.*
FROM
(
SELECT Aisle, VelocityCategory, Sales
FROM VelocityBase Base
LEFT OUTER JOIN [dbo].[VelocitySalesCount] SalesCount
ON Base.ItemId = SalesCount.ItemId
AND Base.ConfigId = SalesCount.ConfigId
AND Base.InventSizeId = SalesCount.InventSizeId
AND Base.InventColorId = SalesCount.InventColorId
AND Base.InventLocationId = SalesCount.InventLocationId
AND SalesCount.DataAreaId = Base.DataAreaId
) VelocityBase
PIVOT ( Sum(Sales) FOR VelocityCategory IN ('+#PivotValues+') ) pvt';
EXECUTE sp_executesql #SQLStatement;
Thanks for the link to the previous question which got me this far.
I usually do not use PIVOT, just "usual" dynamic SQL like this:
DECLARE #sSQL NVARCHAR(MAX)= '' ,
#sSQLSum NVARCHAR(MAX)= '' ,
#sSQlBegin NVARCHAR(MAX)= '
SELECT Aisle, COUNT(*) As ''# SKUs'',
SUM(Sales) As ''# Picks'',
' ,
#sSQLEnd NVARCHAR(MAX)= 'FROM [Dbo].[VelocityBase] Base
LEFT OUTER JOIN [Dbo].[VelocitySalesCount] SalesCount
ON Base.ItemId = SalesCount.ItemId
AND Base.ConfigId = SalesCount.ConfigId
AND Base.InventSizeId = SalesCount.InventSizeId
AND Base.InventColorId = SalesCount.InventColorId
AND Base.InventLocationId = SalesCount.InventLocationId
AND SalesCount.DataAreaId = Base.DataAreaId
GROUP BY Aisle
ORDER BY Aisle' ;
WITH c AS ( SELECT DISTINCT
VelocityCategory N
FROM Dbo.VelocityBase
)
SELECT #sSQLSum = #sSQLSum + 'SUM(CASE WHEN c.N=''' + c.N
+ ''' THEN 1 ELSE 0 END ) AS ''' + c.N + ' SKUs'',' + CHAR(13)
+ 'SUM(CASE WHEN c.N=''' + c.N
+ ''' THEN SALES ELSE 0 END ) AS ''' + c.N + ' Sales'',' + CHAR(13)
FROM c
IF(LEN(#sSQLSum))>0
SET #sSQLSum = LEFT(#sSQLSum, ( LEN(#sSQLsum) - 2 ))
SET #sSQL = #sSQlBegin + #sSQLSum + CHAR(13) + #sSQLEnd
EXEC (#sSQL)
Unless you generate the query dynamically, I don't think there's a way to generate what you want.
Your problem could be solved easily if your tables were normalized. For instance, the VelocityBase table should have a VelocityCategoryID column instead of a VelocityCategory column. This new column should be a foreign key to a new table called VelocityCategory (or something like that) then your query for this calculation becomes almost trivial.