库存库存计算查询或/和优化

时间:2013-11-15 22:43:49

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

Remains - 所有产品交易

Stock - 产品库存

DimDate - 时间表

计算库存:

  1. 选择需要计算库存的日期,示例日期20050115产品 - 1仓库 - 6
  2. 将下个月的第一天示例20050201Stock表格与weightstockcost划分为同一产品和仓库。
  3. Remains中从所选日期到月末的所有交易相加,并从Stock
  4. 中扣除

    下个月的第一天我正在使用它:

    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
    

1 个答案:

答案 0 :(得分:0)

很难判断它是否在较小的数据集上更快,但以下内容看起来有更好的查询计划。方法是只加入库存表一次而不是三次。

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

如果您有机会重新设计此架构,请记住date数据类型仅使用三个字节,而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