SQL股票追踪

时间:2016-09-01 18:02:24

标签: sql-server sql-server-2008

我有一个dbo.StockLocationHistoryTable,如下所示:

SELECT * FROM dbo.StockLocationHistory AS slh    

    StockIdentifier | DateScanned             | WarehouseLocation
    -------------------------------------------------
    72825           | 2016-07-03 16:41:24.077 | 854
    30509           | 2016-07-03 16:41:24.077 | 854
    30509           | 2016-07-05 08:22:10.056 | 854
    30509           | 2016-07-06 14:22:15.099 | 628
    30509           | 2016-07-08 15:28:22.542 | 628
    72825           | 2016-07-08 15:32:25.256 | 778
    30509           | 2016-07-10 18:22:24.556 | 854

前提是每次员工进行库存处理时,都会为该产品和产品所在的位置添加一行。因此,从上表中我们看到产品72825在第3个位置扫描了854然后在778号位置再次扫描。

不幸的是,当软件检测到产品位于与之前扫描不同的位置时,软件不会输入StockOUT记录。我正在尝试(未成功)创建详细说明位置历史记录的位置分类帐。

我只关心何时将股票添加到某个位置并从某个位置移除,而不是临时扫描(EG:第一个代码块中的第3行)。我还需要详细说明如代码区块2所示,当在新位置检测到股票为StockOUT事件时。

我需要的是以下内容:

DECLARE @WarehouseLocation INT = 854

[DateScanned]           | StockIdentifier | EventType | StockLevel
------------------------------------------------------------------
2016-07-03 16:41:24.077 | 30509           | StockIN   | 1
2016-07-03 16:41:24.077 | 72825           | StockIN   | 2
2016-07-06 14:22:15.099 | 30509           | StockOUT  | 1
2016-07-08 15:32:25.256 | 72825           | StockOUT  | 0
2016-07-10 18:22:24.556 | 30509           | StockIN   | 1

1 个答案:

答案 0 :(得分:0)

我强烈建议您考虑获取这些数据的其他方法。原因是SQL变得复杂,在我看来,效果不是很好。您可以考虑结构或表处理中的更改。

如果没有,或许在应用程序级别更容易计算StockLevel(不需要中间表)。

目标表重命名为@t,代码更小。引入“@ intermediate.id”以正确计算StockLevel(因为DateScanned不是唯一的)。 最后“ORDER BY”是为了保证正确的顺序(因为“GROUP BY”并不保证所有情况都这样)。

declare @WarehouseLocation int = 854

declare @intermediate table(id int identity primary key, DateScanned datetime, StockIdentifier int, EventType char(8))

insert @intermediate
select tin.DateScanned, tin.StockIdentifier, 'StockIN' as EventType from @t tin
    where tin.WarehouseLocation = @WarehouseLocation
    and not exists(select * from @t t 
        where t.StockIdentifier = tin.StockIdentifier 
        and t.WarehouseLocation = @WarehouseLocation
        and t.DateScanned < tin.DateScanned
        and not exists(select * from @t tout 
            where tout.StockIdentifier = t.StockIdentifier
            and tout.DateScanned > t.DateScanned and tout.DateScanned < tin.DateScanned
            and tout.WarehouseLocation != @WarehouseLocation))
union all
select tout.DateScanned, tout.StockIdentifier, 'StockOUT' as EventType from @t tout
    where tout.WarehouseLocation != @WarehouseLocation
    and not exists(select * from @t t
        where t.StockIdentifier = tout.StockIdentifier 
        and t.WarehouseLocation != @WarehouseLocation
        and t.DateScanned < tout.DateScanned
        and not exists(select * from @t tin 
            where tin.StockIdentifier = t.StockIdentifier
            and tin.DateScanned > t.DateScanned and tin.DateScanned < tout.DateScanned
            and tin.WarehouseLocation = @WarehouseLocation))
order by DateScanned

select t.DateScanned, t.StockIdentifier, t.EventType,
    sum(case when prev.EventType = 'StockIn' then 1 else -1 end) as StockLevel
from @intermediate t left join @intermediate prev on prev.id <= t.id
group by t.DateScanned, t.StockIdentifier, t.EventType
order by t.DateScanned