MS SQL - Join Multiple Pivots - sql

I am trying to merge multiple pivots together as a single statement.Could you please help how to.
SELECT ID, A as [LglCode-A],B as [LglCode-B],C as [LglCode-C],D as [LglCode-D] from
(
select ID,LglFlg, Code
from #tmp1
) x
pivot
(
max(Legal)
for Code in ([A],[B],[C],[D])
) p;
SELECT ID, A as [MH Code-A],B as [MH Code-B],C as [MH Code-C],D as [MH Code-D] from
(
select ID,[MH Code], Code
from #tmp1
) x
pivot
(
max([MH Code])
for Code in ([A],[B],[C],[D])
) p;
I saw this approach from the link, is it the only better way to do so ?
MS SQL Pivot Another Table Multiple Times

I would suggest conditional aggregation. I think this does what you want:
select id,
max(case when Code = 'A' then lglflg end) as legal_a,
max(case when Code = 'B' then lglflg end) as legal_b,
max(case when Code = 'C' then lglflg end) as legal_c,
max(case when Code = 'D' then lglflg end) as legal_d,
max(case when Code = 'A' then [MH Code] end) as mh_a,
max(case when Code = 'B' then [MH Code] end) as mh_b,
max(case when Code = 'C' then [MH Code] end) as mh_c,
max(case when Code = 'D' then [MH Code] end) as mh_d
from #tmp1
group by id;

You can try the following:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX);
SET #cols = STUFF((select distinct ',
MAX(CASE WHEN [Code]=''' + CAST([Code] as varchar(10)) + ''' THEN [Legal] ELSE 0 END) AS [LglCode-' + CAST([Code] as varchar(10)) + '],
MAX(CASE WHEN [Code]=''' + CAST([Code] as varchar(10)) + ''' THEN [MH Code] ELSE 0 END) AS [MH Code-' + CAST([Code] as varchar(10)) + ']'
/*---------------You can add other columns here similarly--------------*/
FROM #tmp1
FOR XML PATH(''),type).value('.','varchar(max)'),1,2,'')
SET #query = 'SELECT ID, ' + #Cols + ' FROM #tmp1 group by ID'
--print (#query)
exec(#query)
You may need to change a bit here and there as there is no test data available here.

Related

Conditional aggregation referencing table instead of manual entry

I asked a question previously on conditional aggregation. SQL Transform Crosstab Pivot and the answer was great! However, I need to expand on this.
The solution at the time was the following query:
SELECT
Item,
[X] = MAX(CASE WHEN [Columns] = 'X' THEN Result END),
[Y] = MAX(CASE WHEN [Columns] = 'Y' THEN Result END),
[Z] = MAX(CASE WHEN [Columns] = 'Z' THEN Result END)
FROM thisTable
GROUP BY Item
Question: I now have a table TEST with W, X, Y, Z in rows. Instead of adding another line ([W] = MAX(CASE WHEN [Columns] = 'W' THEN Result END)) to the query, can the query above be re-written to refer to the table for the values?
The reason is because I anticipate that there will more than just W, X, Y, Z and want to avoid adding more lines to this query in the future.
if you want to stay with conditional aggregation you can create your query dynamically like this.
DECLARE #Columns NVARCHAR(MAX),
#Sql NVARCHAR(MAX)
SELECT #Columns = STUFF((
SELECT ',' + CONCAT(QUOTENAME([Columns]), ' = MAX(CASE WHEN [Columns] = ''', [Columns], ''' THEN Result END)')
FROM thisTable
GROUP BY [Columns] -- distinct
ORDER BY [Columns] -- order column names
FOR XML PATH('')
), 1, 1, '')
SET #Sql = N'
SELECT Item,
' + #Columns + '
FROM thisTable
GROUP BY Item
'
EXEC(#Sql)
if you want to use DESCRIPTION from TEST as column name you could use this.
SELECT #Columns = STUFF((
SELECT ',' + CONCAT(QUOTENAME([Description]), ' = MAX(CASE WHEN [Columns] = ''', [Columns], ''' THEN Result END)')
FROM TEST
FOR XML PATH('')
), 1, 1, '')

How to format select query output

I have table like this below,
Type Model Year
121232323 Test1 2000
121232323 Test2 2001
I want output like below, how to write query for that.?
121232323 Test1 Test2
2000 2001
Using Simple Pivot we can achieve
DECLARE #Table1 TABLE
( Type int, Model varchar(5), Year int)
;
INSERT INTO #Table1
( Type , Model , Year )
VALUES
(121232323, 'Test1', 2000),
(121232323, 'Test2', 2001)
;
select Type,[Test1],[Test2] from #Table1
PIVOT (MAX(YEAR) FOR MODEL IN ([Test1],[Test2]))PVT
I don't know about Originalnr , but you can do this with conditional aggregation if you have a limited amount of tests :
SELECT t.Type,
MAX(CASE WHEN t.Model = 'Test1' THEN t.Year END) as Test1,
MAX(CASE WHEN t.Model = 'Test2' THEN t.Year END) as Test2
FROM YourTable t
GROUP BY t.Type
Another method other than PIVOT is to use conditional aggregation:
SELECT
Type,
Test1 = MAX(CASE WHEN Model = 'Test1' THEN [year] END),
Test2 = MAX(CASE WHEN Model = 'Test2' THEN [year] END)
FROM tbl
GROUP BY Type
If you have unlimited number of Models you can do it using dynamic crosstab:
DECLARE #sql NVARCHAR(MAX) = N'';
SELECT #sql =
'SELECT
Type' + CHAR(10) +
(SELECT DISTINCT
' , MAX(CASE WHEN Model =''' + Model + ''' THEN [year] END) AS ' + QUOTENAME(Model) + CHAR(10)
FROM tbl
FOR XML PATH('')
) +
'FROM tbl
GROUP BY Type;';
PRINT(#sql);
EXEC(#sql);
ONLINE DEMO

Pivot a fixed multiple column table in sql server

I have a table which I need to pivot for reporting services:
DateCreated Rands Units Average Price Success % Unique Users
-------------------------------------------------------------------------
2013-08-26 0 0 0 0 0
2013-08-27 0 0 0 0 0
2013-08-28 10 2 5 100 1
2013-08-29 12 1 12 100 1
2013-08-30 71 9 8 100 1
2013-08-31 0 0 0 0 0
2013-09-01 0 0 0 0 0
In other words I need to have Rands, Units, Average Price etc at rows and the dates as columns.
I have read various examples but I just can't seem to get it right.
Any help would be much appreciated!
This one will do what you want, but you have to specify all the dates
select
c.Name,
max(case when t.DateCreated = '2013-08-26' then c.Value end) as [2013-08-26],
max(case when t.DateCreated = '2013-08-27' then c.Value end) as [2013-08-27],
max(case when t.DateCreated = '2013-08-28' then c.Value end) as [2013-08-28],
max(case when t.DateCreated = '2013-08-29' then c.Value end) as [2013-08-29],
max(case when t.DateCreated = '2013-08-30' then c.Value end) as [2013-08-30],
max(case when t.DateCreated = '2013-08-31' then c.Value end) as [2013-08-31],
max(case when t.DateCreated = '2013-09-01' then c.Value end) as [2013-09-01]
from test as t
outer apply (
select 'Rands', Rands union all
select 'Units', Units union all
select 'Average Price', [Average Price] union all
select 'Success %', [Success %] union all
select 'Unique Users', [Unique Users]
) as C(Name, Value)
group by c.Name
You can create a dynamic SQL for this, something like this:
declare #stmt nvarchar(max)
select #stmt = isnull(#stmt + ',', '') +
'max(case when t.DateCreated = ''' + convert(nvarchar(8), t.DateCreated, 112) + ''' then c.Value end) as [' + convert(nvarchar(8), t.DateCreated, 112) + ']'
from test as t
select #stmt = '
select
c.Name, ' + #stmt + ' from test as t
outer apply (
select ''Rands'', Rands union all
select ''Units'', Units union all
select ''Average Price'', [Average Price] union all
select ''Success %'', [Success %] union all
select ''Unique Users'', [Unique Users]
) as C(Name, Value)
group by c.Name'
exec sp_executesql #stmt = #stmt
I solved this in the end using dynamic sql, very similar to the marked answer. I wasn't able to find a way of doing this without dynamic sql. The dates had to be in order and the last 7 days, they also had to use the day of the week names (which I didn't specify in the question).
The biggest change I needed to make was changing the table variable into a temporary table.
This is because dynamic sql statements execute in a different context and don't know about any variables you have created.
In the end I was completely off track trying to use PIVOT and APPLY should be used in situations where there are more than one "type" of value.
I have included my solution below since it could help someone who has a similar problem:
CREATE TABLE #SummaryTable
(
[DateCreated] DATE UNIQUE,
[Rands] DECIMAL,
[Units] INT,
[Average Price] DECIMAL,
[Success %] INT,
[Unique Users] INT
);
--Code to fill table
declare #stmt nvarchar(max)
select #stmt = isnull(#stmt + ',', '') +
'max(case when t.DateCreated = ''' + convert(nvarchar(16), t.DateCreated, 126)
+ ''' then c.Value end) as [' + left(datename(dw, t.DateCreated),3) + ']'
from #SummaryTable as t
select #stmt = '
select
c.Name, ' + #stmt + ' from #SummaryTable as t
outer apply (
select ''Rands'', Rands union all
select ''Units'', Units union all
select ''Average Price'', [Average Price] union all
select ''Success'', [Success %] union all
select ''Unique Users'', [Unique Users]
) as C(Name, Value)
group by c.Name'
exec(#stmt)

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.