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.InventLocationI开发者_JS百科d = 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.
精彩评论