根据生效日期选择唯一记录,终止日期以终止日期为准

时间:2019-04-24 14:22:40

标签: sql-server tsql

我有一个有趣的难题,我正在使用SQL Server 2012或SQL Server 2016(显然是T-SQL)。我有一个产品列表,每个产品都有自己的UPC代码。这些产品都有终止日期,并且UPC代码在终止日期之后将回收到新产品中。假设我在Item_UPCs表中具有以下内容:

    Item Key | Item Desc |     UPC    | UPC Discontinue Date
      123456 | Shovel    | 0009595959 | 2018-04-01
      123456 | Shovel    | 0007878787 | NULL
      234567 | Rake      | 0009595959 | NULL

如您所见,我有一个UPC,可以将其回收利用为新产品。不幸的是,我没有项目UPC表的有效日期,但是在项目表中有关于将项目添加到系统的日期。但是让我们忽略它。

这就是我想要做的:

  • 对于直到终止日期的每个库存记录,请显示与该日期关联的唯一UPC。库存记录由“库存日期”,“采购成本”,“采购数量”,“物料描述”和“物料UPC”组成。
  • 终止日期结束后(例如:第二天),开始仅显示生效的UPC。
  • 确保不存在重复数据,并且无论查询中的日期如何,UPC都被真正“附加”到每一行。

以下是库存明细表的示例:

Inv_Key | Trans_Date | Item_Key | Purch_Qty | Purch_Cost
    123 | 2018-05-12 |   123456 |     12.00 | 24.00
    108 | 2018-03-22 |   123456 |      8.00 | 16.00
    167 | 2018-07-03 |   234567 |     12.00 | 12.00

查询示例:

SELECT DISTINCT
     s.SiteID
    ,id.Item_Key
    ,iu.Item_Desc
    ,iu.Item_Department
    ,iu.Item_Category
    ,iu.Item_Subcategory
    ,iu.UPC
    ,iu.UPC_Discontinue_Date
    ,id.Trans_Date
    ,id.Purch_Cost
    ,id.Purch_Qty
FROM Inventory_Details id
INNER JOIN Item_UPCs iu ON iu.Item_Key = id.Item_Key
INNER JOIN Sites s ON s.Site_Key = id.Site_Key

我要查询的真实查询太长了,无法在此处发布。它具有三个CTE和结果查询。这只是一个样机。这是一个示例结果集:

Site_ID | Item_Key | Item_Desc | Item_Department | Item_Category |    UPC     | UPC_Discontinue Date | Trans_Date | Purch_Cost | Purch_Qty
   2457 |   123456 | Shovel    | Digging Tools   |       Shovels | 0009595959 | 2018-04-01           | 2018-03-22 |      16.00 |      8.00
   2457 |   123456 | Shovel    | Digging Tools   |       Shovels | 0007878787 | NULL                 | 2018-03-22 |      16.00 |      8.00
   2457 |   234567 | Rakes     | Garden Tools    |         Rakes | 0009595959 | NULL                 | 2018-07-03 |      12.00 |     12.00
   2457 |   123456 | Shovel    | Digging Tools   |       Shovels | 0007878787 | NULL                 | 2018-05-12 |      24.00 |     12.00

你们中的任何人都知道如何在查询中将UPC“分配”到特定日期范围,然后在以后的每个有效日期“分配”更新的UPC到项目吗?

非常感谢!

1 个答案:

答案 0 :(得分:1)

鉴于您当前的Item_UPC表,您可以使用LAG分析功能从停产日期生成有效的开始日期:

With Effective_UPCs as (
  select [Item_Key]
       , [Item_Desc]
       , [UPC]
       , coalesce(lag([UPC_Discontinue_Date])
           over (partition by [Item_Key]
                     order by coalesce( [UPC_Discontinue_Date]
                                      , datefromparts(9999,12,31))
           ),
           lag([UPC_Discontinue_Date])
           over (partition by [UPC]
                     order by coalesce( [UPC_Discontinue_Date]
                                      , datefromparts(9999,12,31))
         )) [UPC_Start_Date]
       , [UPC_Discontinue_Date]
    from Item_UPCs i
)
select * from Effective_UPCs;

产生以下 Results

| Item_Key | Item_Desc |        UPC | UPC_Start_Date | UPC_Discontinue_Date |
|----------|-----------|------------|----------------|----------------------|
|   123456 |    Shovel | 0007878787 |     2018-04-01 |               (null) |
|   123456 |    Shovel | 0009595959 |         (null) |           2018-04-01 |
|   234567 |      Rake | 0009595959 |     2018-04-01 |               (null) |

此函数会产生一个完全结束的时间间隔,其中开始日期和终止日期都可以为空,表示该时间段对所有时间都有效。要在查询中使用此代码,只需引用Effective_UPCs CTE代替Item_UPCs表,并添加几个附加谓词以考虑有效日期:

SELECT DISTINCT
     s.SiteID
    ,id.Item_Key
    ,iu.Item_Desc
    ,iu.Item_Department
    ,iu.Item_Category
    ,iu.Item_Subcategory
    ,iu.UPC
    ,iu.UPC_Discontinue_Date
    ,id.Trans_Date
    ,id.Purch_Cost
    ,id.Purch_Qty
FROM Inventory_Details id
INNER JOIN Effective_UPCs iu 
   ON iu.Item_Key = id.Item_Key
  and (iu.UPC_Start_Date is null       or iu.UPC_Start_Date < id.Trans_Date)
  and (iu.UPC_Discontinue_Date is null or id.Trans_Date <= iu.UPC_Discontinue_Date)
INNER JOIN Sites s ON s.Site_Key = id.Site_Key

请注意,以上查询使用了部分开放范围(UPC_Start_Date << / strong> trans_date <= UPC_Discontinue_Date而不是<= (对于两个不等式),这可以防止恰好在终止日期发生的交易与上一个和下一个Item_Key记录相匹配。如果恰好在终止日期发生的交易应匹配新记录而不是旧记录,则只需交换两个不等式:

  and (iu.UPC_Start_Date is null       or iu.UPC_Start_Date <= id.Trans_Date)
  and (iu.UPC_Discontinue_Date is null or id.Trans_Date < iu.UPC_Discontinue_Date)

代替

  and (iu.UPC_Start_Date is null       or iu.UPC_Start_Date < id.Trans_Date)
  and (iu.UPC_Discontinue_Date is null or id.Trans_Date <= iu.UPC_Discontinue_Date)