【问题标题】:SQL fill next date (month) with loopSQL用循环填充下一个日期(月)
【发布时间】:2022-01-05 14:59:18
【问题描述】:

我有输入表,需要添加缺失的日期,但不是最大,而是到下一个可用月份。 所以我需要使用循环。

SET @mindate = '2021.01'
SET @maxdate = CAST( GETDATE() AS Date ) --date today as max date
while 
begin
if @mindate => @maxdate 
begin 
break
end
set @mindate = @mindate + 1
end

然后我可以得到 1+.. 但它不会停止到 7 个月

所以我完全陷入了写作循环。

数据表:

有人可以帮忙写代码吗?因为大多数示例都与连接、数据表或一个最大值有关。

【问题讨论】:

  • 2021.01 不是日期。
  • 你不需要一个循环,关系数据库很少需要一个循环来解决问题。请不要发布images 的数据,包括样本数据和所需结果作为文本。如前所述,'2021.01' 只是一个字符串,它不是任何有效的日期。
  • @Stu,如果可以的话,请修改我的解决方案。有没有更好的方法来聚合price_history_boundaries?我知道它不会扩展并且远未准备好生产,但它可能会帮助@Paul 使用其他方法。让他休息一下 :-) 至少,他愿意摆脱循环!
  • 哦,顺便说一句。 @Stu,我对您在短短九个月内取得的成绩印象深刻。伟大的贡献。
  • 感谢大家。是的,我的错 - '2021.01' 不是日期,但我在 BI 中将这种格式用于某些月份的数字,避免使用日期格式。图片 - 我以后会知道的。

标签: sql loops dateadd


【解决方案1】:

Paul,我假设您忘记在模拟数据中指定月份。

我希望下面的代码可以帮助您了解您要完成的工作是多么的重要 :-) 感谢您摆脱循环的意愿。

为了使它更好,我提出了非规范化(注意!):

  • 创建另一列price_valid_until
  • 最新的价格记录将有price_valid_until = '21000101'(又名,遥远的未来)
  • 注册新价格时,用new price_valid_from - 1 day更新以前的价格

这是解决方案,具有相当复杂但高效的查询 (http://sqlfiddle.com/#!18/4ab23/4)

create table price_history(
  SKU varchar(255),
  price_valid_from date,
  price decimal(16, 2)
)

insert into price_history
values
  ('a', '20210101', 10),
  ('a', '20210107', 12),
  ('b', '20210102', 4),
  ('b', '20210110', 2),
  ('b', '20210214', 5);

-- This fiddler won't let me initialize and reference:
-- 
-- declare
--   @from_date date,
--   @to_date   date;
-- 
-- select
--   @from_date = min(date_from),
--   @to_date   = max(date_from)
-- from price_history

with
  date_range as(
    select
      min(price_valid_from) as from_date,
      --
      eomonth(
        max(price_valid_from)
      ) as to_date
    from price_history
  ),
  --
  all_dates as(
    select from_date as date_in_range
    from date_range
    -- ----------
    union all
    -- ----------
    select dateadd(day, 1, date_in_range)
    from all_dates
    where
      date_in_range < (
        select to_date
        from date_range
      )
  ),
  --
  price_history_boundaries as(
    select
      ph.SKU,
      ph.price,
      --
      ph.price_valid_from,
      -- The latest price, so far, is valid until 01/01/2100
      coalesce(
        dateadd(
          day,
          -1,
          min(ph_next.price_valid_from)
        ),
        '21000101'
      ) as price_valid_until
    from
      price_history ph
        left outer join price_history ph_next
        on(
              ph_next.SKU              = ph.SKU
          and ph_next.price_valid_from > ph.price_valid_from
        )
    group by ph.SKU, ph.price_valid_from, ph.price
  )
select
  phb.SKU,
  ad.date_in_range,
  phb.price
from
  all_dates ad
    inner join price_history_boundaries phb
    on(
          phb.price_valid_from  <= ad.date_in_range
      and phb.price_valid_until >= ad.date_in_range
    )
order by phb.SKU, ad.date_in_range

【讨论】:

  • 哇!超级感谢!完美!
  • 所以,@paul,请不要忘记 UPVOTE! :-)
【解决方案2】:

您可以通过创建要加入的日期列表来轻松实现您想要的结果。在这里,我使用递归 CTE 创建日期范围,每次迭代添加 1 个月直到当前日期。

然后加入源数据很简单,这里lead() 可以方便地限制加入的行。另外,假设 SQL Server 使用 Getdate

declare @start date=(select Min([date]) from sourcetable);

with m as (
    select 1 num, @start [Date]
    union all
    select num+1 , DateAdd(month,1,m.[date])
    from m
    where DateAdd(month,1,m.[date]) <= GetDate()
), t as (
    select *, Lead([date],1,GetDate()) over (order by [date]) NextDate
    from sourcetable
)
select m.[Date], t.sku, t.price
from m
join t on m.[date] >= t.[date] and m.[date] < t.nextdate

Working Fiddle

【讨论】:

  • 谢谢!这段代码对我来说看起来更简单。很好,非常感谢!很遗憾我无法将两个答案都标记为正确..
  • 它也只显示 1 个 SKU,但我会更正它,因为我喜欢这个代码 dbfiddle.uk/… 这里我添加了另一个 sku。
  • 没有问题 - 感谢这不是第一个答案,不幸的是家人挡住了路 ;-)。您的示例数据集不足以理解完整的需求或边缘场景,所以如果它不符合您的所有期望,我并不感到惊讶,但所有这些都很容易实现,您也可以在 SKU 上使用lead()。如果对你有帮助,点个赞就好了! :)
  • 嗨 Stu,很抱歉打扰您,尝试更换铅,但由于从未使用过铅,看来我需要更多时间.. 主要问题是我需要 SKU a、b 和其他延长几个月。所以这里是示例 dbfiddle.uk/… ,所以总共查询 12 个句点,但应该是 a 和 b sku,现在它是混合的。但只有一个 sku - 工作正常。如何使用 2 sku .. 工作?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-01-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多