【问题标题】:SQL trying to do a Row Wise Sum in a complicated SQL pivot and dynamic querySQL 尝试在复杂的 SQL 数据透视和动态查询中进行 Row Wise Sum
【发布时间】:2020-01-31 20:39:31
【问题描述】:

我有一个简单的发票表,其中包含每件售出的商品及其售出日期。

以下是获取基本数据库并计算每件商品每周售出次数的一些示例数据。

+------+-----------------+------------+---------+
| Week |   Item_Number   | Color_Code | Touches |
+------+-----------------+------------+---------+
|    1 | 11073900LRGMO   |      02000 |       7 |
|    1 | 11073900MEDMO   |      02000 |       9 |
|    2 | 1114900011BMO   |      38301 |      62 |
|    2 | 1114910012BMO   |      21701 |     147 |
|    2 | 1114910012BMO   |      38301 |     147 |
|    2 | 1114910012BMO   |      46260 |     147 |
|    3 | 13MK430R03R     |      00101 |       2 |
|    3 | 13MK430R03R     |      10001 |       2 |
|    3 | 13MK430R03R     |      65004 |       8 |
|    3 | 13MK430R03S     |      00101 |       2 |
|    3 | 13MK430R03S     |      10001 |       2 |
+------+-----------------+------------+---------+

然后我使用动态查询和数据透视运算符从这些数据中创建了一个矩阵。这是我的做法,

首先,我创建一个临时表

DECLARE @cols AS NVARCHAR(MAX)
DECLARE @query  AS NVARCHAR(MAX)

IF OBJECT_ID('tempdb..#VTable') IS NOT NULL
    DROP TABLE #VTable

CREATE TABLE #VTable 
(
  [Item_Number] NVARCHAR(100), 
  [Color_Code] NVARCHAR(100), 
  [Item_Cost] NVARCHAR(100), 
  [Week] NVARCHAR(10), 
  [xCount] int
);

然后我将我的数据插入到那个表中,

INSERT INTO #VTable
(
  [Item_Number], 
  [Color_Code],
  [Item_Cost],
  [Week], 
  [xCount]
)

SELECT 
*
FROM (
    SELECT
    Item_Number
    ,Color_Code
    ,Item_Cost
    ,Week
    ,Count(Item_Number) Touches
    FROM (

        SELECT

         DATEPART (year, I.Date_Invoiced) Year
        ,DATEPART (month, I.Date_Invoiced) Month
        ,Concat(CASE WHEN DATEPART (week, I.Date_Invoiced) <10 THEN  CONCAT('0',DATEPART (week, I.Date_Invoiced)) ELSE CAST(DATEPART (week, I.Date_Invoiced) AS NVARCHAR) END,'-',RIGHT(DATEPART (year, I.Date_Invoiced),2) )  WEEK
        ,DATEPART (day, I.Date_Invoiced) Day
        ,I.Invoice_Number
        ,I.Customer_Number
        ,I.Warehouse_Code
        ,S.Pack_Type
        ,S.Quantity_Per_Carton
        ,S.Inner_Pack_Quantity
        ,LTRIM(RTRIM(ID.Item_Number)) Item_Number
        ,LTRIM(RTRIM(ID.Color_Code)) Color_Code
        ,CASE 
            WHEN ISNULL(s.Actual_Cost, 0) = 0
                THEN ISNULL(s.Standard_Cost, 0)
                ELSE s.Actual_Cost  
        END Item_Cost
        ,ID.Quantity
        ,case when s.Pack_Type='carton' then id.Quantity/s.Quantity_Per_Carton when  s.Pack_Type='Inner Poly'  then id.Quantity/s.Inner_Pack_Quantity end  qty
        ,ID.Line_Number

        FROM    Invoices I
                LEFT JOIN Invoices_Detail ID on I.Company_Code = ID.Company_Code and I.Division_Code = ID.Division_Code and I.Invoice_Number = ID.Invoice_Number
                LEFT JOIN Style S on I.Company_Code = S.Company_Code and I.Division_Code = S.Division_Code and ID.Item_Number = S.Item_Number and ID.Color_Code = S.Color_Code

        WHERE   1=1
                AND (I.Company_Code = @LocalCompanyCode OR @LocalCompanyCode IS NULL)  
                AND (I.Division_Code = @LocalDivisionCode OR @LocalDivisionCode IS NULL)
                AND (I.Warehouse_Code = @LocalWarehouse OR @LocalWarehouse IS NULL)
                AND (S.Pack_Type = @LocalPackType OR @LocalPackType IS NULL)
                AND (I.Customer_Number = @LocalCustomerNumber OR @LocalCustomerNumber IS NULL)
                AND (I.Date_Invoiced Between @LocalFromDate And @LocalToDate)
    ) T
    GROUP BY Item_Number,Color_Code,Item_Cost,Week
) TT

然后我使用动态查询来创建矩阵:

select @cols = STUFF((SELECT ',' + QUOTENAME(Week) 
                    from #VTable
                    group by Week
                    order by (Right(Week,2) + LEFT(Week,2))
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')


set @query = '
                SELECT 
                * 
                FROM (
                    SELECT Item_Number,Color_Code, Item_Cost,' + @cols + ' from 
                     (
                        select Item_Number, Color_Code, Item_Cost, week, xCount
                        from #Vtable
                    ) x
                    pivot 
                    (
                        sum(xCount)
                        for week in (' + @cols + ')
                    ) p 
                )T
            '

execute(@query);

这给了我我正在寻找的东西,这是矩阵的样子。

+---------------+------------+-----------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+
|  Item_Number  | Color_Code | Item_Cost | 36-18 | 37-18 | 38-18 | 39-18 | 40-18 | 41-18 | 42-18 | 43-18 | 44-18 | 45-18 | 46-18 | 47-18 | 48-18 | 49-18 | 50-18 | 51-18 | 52-18 | 53-18 | 01-19 | 02-19 | 03-19 | 04-19 | 05-19 | 06-19 | 07-19 | 08-19 | 09-19 | 10-19 | 11-19 | 12-19 | 13-19 | 14-19 | 15-19 | 16-19 | 17-19 | 18-19 | 19-19 | 20-19 | 21-19 | 22-19 | 23-19 | 24-19 | 25-19 | 26-19 | 27-19 | 28-19 | 29-19 | 30-19 | 31-19 | 32-19 | 33-19 | 34-19 | 35-19 |
+---------------+------------+-----------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+
| 11073900LRGMO |      02000 | 8.51      |     1 | NULL  |    13 | NULL  |     3 | NULL  | NULL  |     3 |     3 | NULL  |     4 | 3     |     6 | NULL  |     4 | NULL  | NULL  | NULL  |     7 |     4 | NULL  | 3     |     2 |     5 |    30 |     7 |     3 |    10 | NULL  |     9 |    19 |     5 | NULL  |    10 |     9 |     5 |     2 |     3 |     5 |     4 |     3 |     9 |     7 | NULL  |     5 |     1 | 3     |     5 | NULL  | NULL  |    11 |     7 |     3 |
| 11073900MEDMO |      02000 | 8.49      |    11 | NULL  |    22 | NULL  |     5 | NULL  | NULL  |    14 |     4 | NULL  |     4 | 3     |     8 | NULL  |     9 | NULL  | NULL  | NULL  |     9 |     3 | NULL  | 7     |     6 |     4 |    37 |    10 |     8 |     9 | NULL  |     7 |    30 |    14 | NULL  |    12 |     5 |     7 |     8 |     7 |     2 |     4 |     6 |    15 |     4 | NULL  |     2 |     7 | 3     |     7 | NULL  | NULL  |    11 |     9 |     3 |
| 11073900SMLMO |      02000 | 8.50      |     6 | NULL  |    18 | NULL  |     3 | NULL  | NULL  |     3 |     7 | NULL  |     5 | NULL  |     7 | NULL  |     9 | NULL  | NULL  | NULL  |     7 |     4 | NULL  | 7     |     2 |     6 |    37 |     9 |     4 |     7 | NULL  |     7 |    19 |     7 | NULL  |    11 |     5 |     7 |     7 |     2 |     3 |     8 |     8 |     9 |     2 | NULL  |     2 |     2 | 2     |     4 | NULL  | NULL  |     8 |     5 |     4 |
| 11073900XLGMO |      02000 | 8.51      |     2 | NULL  |     6 | NULL  |     3 | NULL  | NULL  |     2 |     4 | NULL  |     3 | 1     |     3 | NULL  |     4 | NULL  | NULL  | NULL  |     4 |     4 | NULL  | NULL  |     3 |     1 |    27 |     4 |     3 |     4 | NULL  |     8 |    11 |     9 | NULL  |     7 |     2 |     4 |     1 |     5 |     1 |     6 |     5 |     6 |     1 | NULL  |     1 |     3 | NULL  |     3 | NULL  | NULL  |     3 |     4 |     2 |
+---------------+------------+-----------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+

我要做的最后一件事是找到一种对这张表进行排序的好方法。我认为最好的方法是按照在所有星期中选择最多的项目编号进行排序。逐列求和将为我提供所有项目每周的触摸总数,但我想做一个逐行求和,其中最后有另一列包含每个项目的触摸。有谁知道我会怎么做?我尝试过使用此链接中的另一个动态查询 -> (calculate Row Wise Sum - Sql server) 但我无法让它工作。

【问题讨论】:

  • 您只是在问如何将订单添加到您的动态 sql 中吗?
  • 不,我想创建一个名为 totalCount 之类的新列,它将每个项目的每周计数求和(因此按行排列),然后按该列排序。
  • 为什么不直接创建另一个变量,如@cols,用+而不是逗号分隔?然后你只需将它添加到你的动态 sql 中,它就会将所有列添加在一起。在这一点上,顺序应该是微不足道的。

标签: sql sql-server dynamic pivot


【解决方案1】:

这是一个基于this answer 的快速而简单的解决方案,用于对您的wk-yr 列进行“合并总和”。这不会修改您现有的代码,但为了提高效率,最好按照@Sean Lange 的建议。

在最新的 SQL Server 2017(linux docker 映像)上测试。

输入数据集

(为简单起见,这里只有 3 个 wk-yr 列。代码应该适用于任意数量的列):

create table WeeklySum (
    Item_Number varchar(50),
    Color_Code varchar(10),
    Item_Cost float,
    [36-18] float,
    [37-18] float,
    [38-18] float 
)

insert into WeeklySum (Item_Number, Color_Code, Item_Cost, [36-18], [37-18], [38-18])
values ('11073900LRGMO', '02000', 8.51,  1, NULL,  13),
        ('11073900MEDMO', '02000', 8.49, 11, NULL,  22),
        ('11073900SMLMO', '02000', 8.50,  6, NULL,  18),
        ('11073900XLGMO', '02000', 8.51,  2, NULL,   6);

select * from WeeklySum;

示例代码

/* 1. Expression of the sum of coalesce(wk-yr, 0) */
declare @s varchar(max);

-- In short, this query select wanted columns by exclusion in sys.columns
-- and then do the "coalesce sum" over the selected columns in a row.
-- The "@s = coalesce()" expression is to avoid redundant '+' at beginning.
-- NOTE: May have to change sys.columns -> syscolumns for SQL Server 2005 
--       or earlier versions
select @s = coalesce(@s + ' + coalesce([' + C.name + '], 0)', 'coalesce([' + C.name + '], 0)')
from sys.columns as C
where C.object_id = (select top 1 object_id from sys.objects
                     where name = 'WeeklySum')
  and C.name not in ('Item_Number', 'Color_Code', 'Item_Cost');
print @s;

/* 2. Perform the sorting query */
declare @sql varchar(max);
set @sql = 'select *, ' + @s + ' as totalCount ' +
    'from WeeklySum ' +
    'order by totalCount desc';
print @sql;
execute(@sql);

输出

| Item_Number   | Color_Code | Item_Cost | 36-18 | 37-18 | 38-18 | totalCount |
|---------------|------------|-----------|-------|-------|-------|------------|
| 11073900MEDMO | 02000      | 8.49      | 11    | NULL  | 22    | 33         |
| 11073900SMLMO | 02000      | 8.5       | 6     | NULL  | 18    | 24         |
| 11073900LRGMO | 02000      | 8.51      | 1     | NULL  | 13    | 14         |
| 11073900XLGMO | 02000      | 8.51      | 2     | NULL  | 6     | 8          |

还要检查消息窗口中生成的表达式:

@s:

coalesce([36-18], 0) + coalesce([37-18], 0) + coalesce([38-18], 0) as totalCount

@sql:

select *, coalesce([36-18], 0) + coalesce([37-18], 0) + coalesce([38-18], 0) as totalCount from WeeklySum order by totalCount desc

【讨论】:

    猜你喜欢
    • 2018-06-25
    • 2013-10-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多