0

我有一个跟踪小部件位置的数据库(即跟踪单个项目而不是简单的 SKU 计数的库存系统)。

有两个相关的表:

 InventoryUpdates (
     UpdateId   bigint PRIMARY KEY,
     LocationId bigint,
     Type       tinyint, -- an enum column
     DateTime   datetimoffset
 )

 WidgetState {
     SerialNumber varchar(20) PRIMARY KEY,
     UpdateId     bigint
 }

解释:

库存更新可以是“完成”、“添加”或“减法”(这由Type列确定)。当 Update 为Complete时,它意味着相关的集合WidgetState代表整个库存(即,如果列出了一个小部件,那么它就在那里;并且没有一个小部件是肯定的验证它当时不存在于库存中)。当 Update 为Additive时,表示需要通过汇总Additive自上次Complete更新以来的所有后续更新来确定 Inventory(就像增量备份一样),最后Subtractive更新意味着应将更新中包含的那些项目从清单中排除。当然,更新后可以出现多个Additive和更新。SubtractiveComplete

所以我的问题是:

“给定最后一次Complete更新和所有后续AdditiveSubtractive更新的集合,获取一个位置的当前库存”

数据如下所示:

InventoryUpdates
----------------------------------------------
UpdateId   LocationId  Type         DateTime
1          1           Complete     2014-01-01
2          1           Additive     2014-01-02
3          1           Subtractive  2014-01-03
4          1           Additive     2014-01-04

WidgetState
----------------------------------------------
SerialNumber  UpdateId
0001          1
0004          1
008B          2
0001          3
0004          3
0004          4

在这个简单的示例中,我们看到唯一的小部件0004在更新 1 的库存中是已知的,然后它在更新 3 中被删除,然后在更新 4 中重新添加。

假设我想找出当前库存,我的结果集应该是:

WidgetsInInventory
----------------------------------------------
SerialNumber
0004
008B

可能有一个非常简单的解决方案,我现在想不出。我想它可能看起来像这样:

SELECT
    DISTINCT SerialNumber,
    Type 
FROM
    WidgetState
    INNER JOIN InventoryUpdates ON WidgetState.UpdateId = InventoryUpdates.UpdateId
WHERE
    InventoryUpdates.Type = Complete OR
    InventoryUpdates.Type = Additive
ORDER BY
    InventoryUpdates.DateTime DESC

EXCEPT

SELECT
    DISTINCT SerialNumber,
    Type 
FROM
    WidgetState
    INNER JOIN InventoryUpdates ON WidgetState.UpdateId = InventoryUpdates.UpdateId
WHERE
    InventoryUpdates.Type = Subtractive
ORDER BY
    InventoryUpdates.DateTime DESC

...但是当减法发生时,它就会分崩离析,而不管它可能发生在比后续加法更早的 DateTime 值的情况下。

更新

我只是在回家的路上想到这可能是一个可行的解决方案,我明天会测试它。

下面的代码使用DISTINCT组合 withORDER BY来获得each的最后一次出现WidgetState,所以如果最后一次出现是 anAddition那么它将取消任何 previous Subtraction,反之亦然(好吧,如果最后一次出现是 aSubtraction那么它可以很容易地被排除在外)来自带有WHERE Type <> Subtractive谓词的未来超级查询)。03:00h 刚刚过去,我还没有机会尝试,但是这个理论听起来对吗?谢谢!

SELECT
    WidgetState.SerialNumber,
    InventoryUpdates.Type
FROM
    WidgetState
    INNER JOIN InventoryUpdates ON WidgetState.UpdateId = InventoryUpdates.UpdateId
WHERE
    InventoryUpdates.DateTime >= @dateTimeOfLastCompleteUpdate
    AND
    InventoryUpdates.LocationId >= @locationId
GROUP BY
    SerialNumber
ORDER BY
    InventoryUpdates.DateTime DESC
4

2 回答 2

1

我会以不同的方式处理它。简单地计算小部件。如果更新是减法,则输入 -1,而对于完全和加法,则输入 1。然后简单地对标志求和并过滤那些不为零(正)和的标志。

declare @dateTimeOfLastCompleteUpdate Date = '20140101'
declare @locationId int  = 1
;
with cte1 as
(
  select
    ws.SerialNumber,
    ws.UpdateId,
    CASE WHEN iu.Type = 'Subtractive' THEN -1 ELSE 1 END as Flag
  from 
    InventoryUpdates iu
    inner join WidgetState ws
      on ws.UpdateId = iu.UpdateId
  where
    iu.[DateTime] >= @dateTimeOfLastCompleteUpdate
    and iu.LocationId = @locationId
)
, cte2 as
(
  select
    SerialNumber,
    Flag,
    ROW_NUMBER() OVER(partition by SerialNumber order by UpdateId) as rn
  from
    cte1
)
, cte3 as
(
  select
    SerialNumber,
    sum(flag) as WidgetCount
  from 
    cte2 a
  where
    not exists 
    (
      select * 
      from cte2 b 
      where b.serialnumber = a.serialnumber
      and b.rn = a.rn - 1
      and b.flag = a.flag
    )
  group by
    SerialNumber
)
select SerialNumber from cte3 where WidgetCount = 1

这是小提琴

于 2014-03-07T22:28:07.153 回答
0

我做了一些研究,发现LAST_VALUE与 结合使用OVER ... PARTITION BY,但LAST_VALUE仅在 SQL Server 2012 上受支持。我使用的是 2008 R2,所以我需要找到等效的东西。

幸运的是:您可以添加ROW_NUMBER到 aPARTITION然后WHERE rowNumber = 1在正确排序时选择最高值 ( ),所以这是我的最终查询:

SELECT
    *
FROM
    (
    SELECT
        WidgetStates.TId,
        InventoryUpdates.*,
        ROW_NUMBER() OVER (PARTITION BY WidgetStates.Tid ORDER BY InventoryUpdates.DateTime DESC) AS RowN
    FROM
        WidgetStates
        INNER JOIN InventoryUpdates ON WidgetStates.UpdateId = InventoryUpdates.UpdateId
    WHERE
        InventoryUpdates.DateTime >= @lastCompleteUpdateDateTime
        AND
        InventoryUpdates.LocationId = @locationId
    ) As Results
WHERE
    Results.RowN = 1
    AND
    Results.Type >= 0
于 2014-03-20T19:44:47.097 回答