开发者

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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜