简体   繁体   English

动态多列SQL

[英]Dynamic Multi-Column SQL

I have two tables with structures like this: 我有两个具有如下结构的表:

VelocityBase VelocityBase

Aisle | 过道| ItemId | ItemId | ConfigId | ConfigId | InventSizeId | InventSizeId | InventColorId | InventColorId | InventLocationId | InventLocationId | DataAreaId | DataAreaId | VelocityCategory VelocityCategory

VelocitySalesCount VelocitySalesCount

ItemId | ItemId | ConfigId | ConfigId | InventSizeId | InventSizeId | InventColorId | InventColorId | InventLocationId | InventLocationId | DataAreaId | DataAreaId | Sales 销售

Every row in the Base table represents a SKU and the sum of the related SalesCount records' "Sales" fields determines the "Picks". 基本表中的每一行都代表一个SKU,并且相关SalesCount记录的“销售”字段的总和决定了“选择”。 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. 这样,如果用户添加了以“ Lukewarm”作为行速类别的行,则该数据将出现两个新列。

I'm not sure if something like SQL to generate SQL or maybe a PIVOT function would do the trick. 我不确定是否可以使用类似SQL的方法来生成SQL或PIVOT函数。

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: 我通常不使用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)

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. 例如, VelocityBase表应具有VelocityCategoryID列而不是VelocityCategory列。 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. 此新列应该是名为VelocityCategory (或类似名称)的新表的foreign key ,因此您对此计算的查询几乎变得无关紧要。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM