【问题标题】:Inventory stock calculation query or/and optimization库存库存计算查询或/和优化
【发布时间】:2013-11-16 07:51:39
【问题描述】:

Remains - 产品的所有交易

Stock - 产品库存

DimDate - 时间表

库存计算:

  1. 取需要计算库存的日期,例如日期20050115产品-1仓库-6
  2. 以下个月第一天的示例20050201Stock 表为同一产品和仓库的weightstockcost 取一行。
  3. Remains 中从选定日期到月底的所有交易相加,并从Stock 表的取行中减去

下个月的第一天我使用这个:

CONVERT(VARCHAR(25),DATEADD(dd,-(DAY(DATEADD(mm,1,CAST(convert(varchar,t.DateKey) as datetime)))-1),DATEADD(mm,1,CAST(convert(varchar,t.DateKey) as datetime))),112)

例如Remains:

|  TIMEKEY | PRODUCT | WAREHOUSE | COST | STOCK | WEIGHT |
|----------|---------|-----------|------|-------|--------|
| 20050114 |       1 |         6 |  100 |     5 |     15 |
| 20050118 |       1 |         6 |  200 |    10 |     30 |
| 20050125 |       1 |         6 | -100 |    -5 |    -15 |

Stock:

|  TIMEKEY | PRODUCT | WAREHOUSE | COST | STOCK | WEIGHT |
|----------|---------|-----------|------|-------|--------|
| 20050201 |       1 |         6 |  515 |    55 |     53 |
| 20050301 |       2 |         8 |   20 |     3 |      2 |
| 20050301 |       3 |         9 |   16 |     2 |      3 |
| 20050301 |       4 |        10 |   49 |     8 |      5 |
| 20050401 |       5 |        26 |   59 |     9 |     10 |

结果(我的查询)按天计算产品 1、仓库 6 和第一个月的库存:

|  DATEKEY | PRODUCT | WAREHOUSE | WEIGHT |  STOCK |   COST |
|----------|---------|-----------|--------|--------|--------|
| 20050101 |       1 |         6 |     23 |     45 |    315 |
| 20050102 |       1 |         6 |     23 |     45 |    315 |
| 20050103 |       1 |         6 |     23 |     45 |    315 |
| 20050104 |       1 |         6 |     23 |     45 |    315 |
| 20050105 |       1 |         6 |     23 |     45 |    315 |
| 20050106 |       1 |         6 |     23 |     45 |    315 |
| 20050107 |       1 |         6 |     23 |     45 |    315 |
| 20050108 |       1 |         6 |     23 |     45 |    315 |
| 20050109 |       1 |         6 |     23 |     45 |    315 |
| 20050110 |       1 |         6 |     23 |     45 |    315 |
| 20050111 |       1 |         6 |     23 |     45 |    315 |
| 20050112 |       1 |         6 |     23 |     45 |    315 |
| 20050113 |       1 |         6 |     23 |     45 |    315 |
| 20050114 |       1 |         6 |     38 |     50 |    415 |
| 20050115 |       1 |         6 |     38 |     50 |    415 |
| 20050116 |       1 |         6 |     38 |     50 |    415 |
| 20050117 |       1 |         6 |     38 |     50 |    415 |
| 20050118 |       1 |         6 |     68 |     60 |    615 |
| 20050119 |       1 |         6 |     68 |     60 |    615 |
| 20050120 |       1 |         6 |     68 |     60 |    615 |
| 20050121 |       1 |         6 |     68 |     60 |    615 |
| 20050122 |       1 |         6 |     68 |     60 |    615 |
| 20050123 |       1 |         6 |     68 |     60 |    615 |
| 20050124 |       1 |         6 |     68 |     60 |    615 |

问题/疑问 产品库存没有结束,所以我需要显示整个月的结果(或我在 where 子句中选择的范围),而不仅仅是 24 天。如果这是不可能的,也许有人可以帮助我用于计算库存的当前查询优化。我正在使用 ms sql 2008r2

SQLFIDDLEExample

SELECT t.DateKey, r.Product, r.Warehouse,
(SELECT [Weight]
FROM Stock
WHERE Timekey = CONVERT(VARCHAR(25),DATEADD(dd,-(DAY(DATEADD(mm,1,CAST(convert(varchar,t.DateKey) as datetime)))-1),DATEADD(mm,1,CAST(convert(varchar,t.DateKey) as datetime))),112)
AND Product = r.Product
AND Warehouse = r.Warehouse)-SUM(r.Weight) AS [Weight],
(SELECT Stock
FROM Stock
WHERE Timekey = CONVERT(VARCHAR(25),DATEADD(dd,-(DAY(DATEADD(mm,1,CAST(convert(varchar,t.DateKey) as datetime)))-1),DATEADD(mm,1,CAST(convert(varchar,t.DateKey) as datetime))),112)
AND Product = r.Product
AND Warehouse = r.Warehouse)-SUM(Stock) as Stock,
(SELECT Cost
FROM Stock
WHERE Timekey = CONVERT(VARCHAR(25),DATEADD(dd,-(DAY(DATEADD(mm,1,CAST(convert(varchar,t.DateKey) as datetime)))-1),DATEADD(mm,1,CAST(convert(varchar,t.DateKey) as datetime))),112)
AND Product = r.Product
AND Warehouse = r.Warehouse)-SUM(Cost) AS Cost
FROM DimDate t, Remains r
WHERE t.DateKey < r.Timekey
AND r.Timekey <= CONVERT(VARCHAR(25),DATEADD(dd,-(DAY(DATEADD(mm,1,CAST(convert(varchar,t.DateKey) as datetime)))-1),DATEADD(mm,1,CAST(convert(varchar,t.DateKey) as datetime))),112)
AND t.DateKey >= 20050101
and r.Product = '1'
and r.Warehouse = 6
GROUP BY t.DateKey, r.Product, r.Warehouse

【问题讨论】:

    标签: sql sql-server sql-server-2008 tsql optimization


    【解决方案1】:

    很难说它在小数据集上是否更快,但以下看起来有更好的查询计划。方法是只加入股票表一次而不是三次。

    with x as (
        select
            t.DateKey, 
            r.Product, 
            r.Warehouse, 
            sum(r.Weight) as Weight,
            sum(Stock) as Stock,
            sum(Cost) as Cost,
            (t.DateKey / 100 
                + Case t.DateKey / 100 % 100 when 12 Then 89 else 1 end) 
                * 100 + 1 as TimeKey
        from
            DimDate t, 
            Remains r
        where
            t.DateKey < r.Timekey and 
            r.Timekey <= (
                t.DateKey / 100 
                    + Case t.DateKey / 100 % 100 when 12 Then 89 else 1 end) 
                    * 100 + 1 and 
            t.DateKey >= 20050101 and 
            r.Product = 1 and 
            r.Warehouse = 6
        group by
            t.DateKey, 
            r.Product, 
            r.Warehouse
    ) select
        x.DateKey,
        x.Product,
        x.Warehouse,
        s.Weight - x.Weight as Weight,
        s.Stock - x.Stock as Stock,
        s.Cost - x.Cost as Cost
    From
        x
            left outer join
        Stock s
            on s.TimeKey = x.TimeKey and
               s.Product = x.Product and
               s.Warehouse = x.Warehouse;
    

    Example SQLFiddle

    如果您有机会重新设计此架构,请记住日期数据类型仅使用三个字节,而 int 则使用四个字节。

    它可能对整体查询成本贡献不大,但您可以将“下个月开始”值存储为 DimDate 表中的计算列。它使查询更易于阅读。

    create table DimDate (
        [DateKey] int,
        StartOfNextMonthKey as (
                DateKey / 100 
                + Case DateKey / 100 % 100 when 12 Then 89 else 1 end
            ) * 100 + 1 persisted
    );
    

    那么查询是

    with x as (
        select
            t.DateKey, 
            r.Product, 
            r.Warehouse, 
            sum(r.Weight) AS [Weight],
            sum(Stock) as Stock,
            sum(Cost) AS Cost,
            t.StartOfNextMonthKey
        from
            DimDate t, 
            Remains r
        where
            t.DateKey < r.Timekey AND 
            r.Timekey <= t.StartOfNextMonthKey and 
            t.DateKey >= 20050101 and 
            r.Product = 1 and 
            r.Warehouse = 6
        group by
            t.DateKey, 
            r.Product, 
            r.Warehouse,
            t.StartOfNextMonthKey
    ) select
        x.DateKey,
        x.Product,
        x.Warehouse,
        s.Weight - x.Weight as Weight,
        s.Stock - x.Stock as Stock,
        s.Cost - x.Cost as Cost
    From
        x
            left outer join
        Stock s
            on s.TimeKey = x.StartOfNextMonthKey and
               s.Product = x.Product and
               s.Warehouse = x.Warehouse;
    

    Example SQLFiddle

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-11-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多