动态多列SQL

时间:2011-09-30 14:11:00

标签: sql sql-server sql-server-2008

我有两个表格,结构如下:

VelocityBase

过道| ItemId |配置| InventSizeId | InventColorId | InventLocationId | DataAreaId | VelocityCategory

VelocitySalesCount

ItemId |配置| InventSizeId | InventColorId | InventLocationId | DataAreaId |销售

Base表中的每一行代表一个SKU,相关SalesCount记录“Sales”字段的总和决定了“Picks”。此查询有效:

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

但是,列是硬编码的。我想要的是根据此列的数据库中存在的值生成“热”,“暖”,“冷”等。这样,如果用户添加了一个具有“Lukewarm”作为VelocityCategory的行,则会出现两个带有该数据的新列。

我不确定生成SQL或者PIVOT函数之类的SQL是否可以解决问题。

提前致谢!

编辑:

我正在缩小范围。我用这个得到了销售总和数字:

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; 

感谢前一个问题的链接让我走到了这一步。

2 个答案:

答案 0 :(得分:1)

我通常不使用PIVOT,只是这样的“通常”动态SQL:

     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)

答案 1 :(得分:0)

除非您动态生成查询,否则我认为没有办法生成您想要的内容。

如果您的表格已正常化,您的问题可以轻松解决。例如,VelocityBase表应该有VelocityCategoryID列,而不是VelocityCategory列。这个新列应该是foreign key到一个名为VelocityCategory的新表(或类似的东西),那么您对此计算的查询几乎是微不足道的。