T-Sql笛卡尔联接以填充日期并联接到CTE以获取最新

时间:2018-10-22 19:47:05

标签: sql sql-server tsql

我们当前的计算缺货的方法不再适用于我们如何跟踪库存以及如何查看数据。我要使用的新方法是只查看过去一年中每一天的最终OnHandAfter值。我们不是24/7,因此每天结束时输入的最后一个值将告诉我们该商品当天是否缺货。 如果某商品在某个日期没有库存交易,则应使用上次找到的日期

  • 我当前的查询对所有项目进行交叉联接(我目前有 它设置为一个要测试的项目)和一个日历表。这给 我每个项目365天。可以了
  • 我的cte查询针对每个日期返回最终的OnHandAfter 交易。如果单独运行,这将正常工作。
  • 注释掉<=日期条件后,我返回了365行,但 来自cte的日期为NULL。如果条件未注释掉0 返回行。
  • 请注意,下一步是包括OnHandAfter字段,但现在我 似乎无法连接CTE。

ABDailyCalendar abdc
这是表格,其中预填了过去一年中的每个日期

库存数据样本(如果cte单独运行,那么cte会返回单个项目的内容,为简便起见,我省略了一些列)

ItemCode    TransactionDate OnHandAfter rn
Item-123    10/1/2018       960         1
Item-123    9/28/2018       985         1
Item-123    9/27/2018       1085        1
Item-123    9/26/2018       1485        1
Item-123    9/24/2018       1835        1
Item-123    9/20/2018       2035        1
Item-123    9/18/2018       2185        1
Item-123    9/14/2018       2305        1
Item-123    9/13/2018       2605        1

我的查询

with cte as 
(
Select TOP 1 * from
(
    Select 
         ItemCode
        ,convert(Date,TransactionDate) TransactionDate
        ,TransactionType
        ,TransactionQuantity
        ,OnHandBefore
        ,OnHandAfter
        ,ROW_NUMBER() over (partition by ItemCode, CONVERT(Date, TransactionDate) order by TransactionDate DESC) as rn
    from InventoryTransaction
    where TransactionType in (1,2,4,8)
) as ss
where rn = 1
order by TransactionDate DESC
)
SELECT 
     ab.ExternalId
    ,abdc.[Date]
    ,cte.TransactionDate
     From ABItems ab CROSS JOIN ABDailyCalendar abdc
     FULL OUTER JOIN cte on cte.ItemCode = ab.ExternalId --and cte.TransactionDate <= abdc.[Date]
Where ab.ExternalID = 'Item-123'
order by abdc.[Date] DESC

当前样品结果

ExternalId  Date        TransactionDate
Item-123    9/30/2018   NULL
Item-123    9/29/2018   NULL
Item-123    9/28/2018   NULL
Item-123    9/27/2018   NULL
Item-123    9/26/2018   NULL
Item-123    9/25/2018   NULL
Item-123    9/24/2018   NULL

所需结果

ExternalId  Date        TransactionDate
Item-123    9/30/2018   9/28/2018
Item-123    9/29/2018   9/28/2018
Item-123    9/28/2018   9/28/2018
Item-123    9/27/2018   9/27/2018
Item-123    9/26/2018   9/26/2018
Item-123    9/25/2018   9/24/2018
Item-123    9/24/2018   9/24/2018

TransactionDate应该是最新的TransactionDate,它是{=到Date的地方。

如果有关系-我正在运行连接到SQL Server 2008的SSMS 2012。

任何指针或想法将不胜感激。我盯着它看了很久,以至于没有新的东西出现。谢谢。

1 个答案:

答案 0 :(得分:0)

我使用了postgres,但此操作与SQLS大致相同。这是我在评论中所写内容的暗示:

https://www.db-fiddle.com/f/uKcgh9yZVvvqfRWTERv2a3/0

我们在小提琴的左侧制作了一些样本数据。这是特定于PG的,但不要太在意-最终结果是它到达的位置与SQLS中的数据相同

然后查询:

SELECT 
  itemcode, 
  caldate, 
  case when caldate = transactiondate then onhandafter else prev_onhandafter end as onhandat,
  case when caldate = transactiondate then 'tran occurred today, using current onhandafter' else 'no tran today, using previous onhandafter' end as reasoning,
  transactiondate,
  onhandafter,
  prev_onhandafter

FROM
(
  SELECT 
    itemcode, 
    transactiondate, 
    LAG(transactiondate) over(partition by itemcode order by transactiondate) as prev_transactiondate,
    onhandafter,
    LAG(onhandafter) over(partition by itemcode order by transactiondate) as prev_onhandafter
  FROM 
    t
) t2
  INNER JOIN
  c
  ON 
    c.caldate > t2.prev_transactiondate and c.caldate <= t2.transactiondate
ORDER BY itemcode, caldate

itemcode / externalid(两者都被称为

一堆日期-您的日期是DATE还是DATETIME,它们是可比较的。如果需要,将DATETIME强制转换为DATE并没有什么害处,并且如果您的任何日期包含时间分量,则这样做很重要,因为2018-01-01 00 :00不是与2018年1月1日 01 :00相同,并且如果您的日历表具有午夜,并且transactiondate是凌晨1点,则范围联接条件(caldate > prevtrandate and caldate <= trandate)将不起作用正确地出来。随意将其作为联接的一部分进行转换:caldate > CAST(prevtrandate as DATE) and caldate <= CAST(trandate as DATE)。如果可以确保您的日期时间100%准确地在午夜(微秒),那么连接将成功进行而无需强制转换-此处的强制转换是缩短时间并确保苹果与苹果进行比较的快速技巧

好的,这是如何工作的:

我没有使用cte对表中的行进行编号并将其自身连接在一起,而是使用了类似的技术,使用LAG来获取我感兴趣的上一行的值。上一章被定义为“按项目代码递增转换顺序”。这为我们提供了具有当前日期,前一个日期的行(注意:第一行为null,如果需要的话,则需要一些额外的查询,例如COALESCE(lag(...),trandate))保留下来,否则加入后就会消失。我们将使用日期对加入,稍后我们将选择显示当前的还是先前的。

此操作作为子查询完成,因此可以使用上一个值。它在日历日期大于上一个日期且小于或等于当前日期的日期加入日历表。这意味着笛卡尔乘积会填补交易日期中的所有空白,因此我们可以从日历表中获得一组连续的日期。

我们使用一种情况来检查数据-如果校准日期等于转换日期,我们将使用新值作为现值,因为今天发生了转换并减少了库存。否则,我们可以断言今天没有交易,而应该使用prev on hand。

希望这对于您想要的东西来说是正确的(您似乎表明这是您真正想要的事,但是您想要的查询输出只提到了交易日期/日期对

编辑:好的,延迟不可用-这是一个使用行号的解决方案:

https://www.db-fiddle.com/f/2ooVrNF18stUQAa4HyTj6r/0

  WITH cte AS(
  SELECT 
    itemcode, 
    transactiondate, 
    ROW_NUMBER() over(partition by itemcode order by transactiondate) as rown,
    onhandafter
  FROM 
    t
)

SELECT 
  curr.itemcode, 
  c.caldate, 
  case when c.caldate = curr.transactiondate then curr.onhandafter else prev.onhandafter end as onhandat,
  case when c.caldate = curr.transactiondate then 'tran occurred today, using current onhandafter' else 'no tran today, using previous onhandafter' end as reasoning,
  curr.transactiondate,
  curr.onhandafter,
  prev.onhandafter

FROM
  cte curr
  INNER JOIN
  cte prev
  ON curr.rown = prev.rown + 1 and curr.itemcode = prev.itemcode
  INNER JOIN
  c
  ON 
    c.caldate > prev.transactiondate and c.caldate <= curr.transactiondate
  ORDER BY curr.itemcode, c.caldate

工作原理:与我的第一句话差不多。我们按转换日期的顺序将表分为项目代码和行号。我们将此操作作为CTE,因此from cte curr inner join cte prev on curr.rownumber = prev.rownumber+1

这样就模​​拟了

滞后-我们有一排包含当前值和先前值的行。其余查询逻辑从上方保持不变