【问题标题】:How would I conditionally insert a row based on the previous row?如何根据前一行有条件地插入一行?
【发布时间】:2020-12-03 18:16:21
【问题描述】:

我目前正在尝试弄清楚如何根据前一行有条件地插入一行。我相当习惯于使用窗口函数,我想我必须这样做才能使它工作,但我不知道任何其他函数可以使它工作。

我正在使用的数据集如下所示

我希望它看起来像这样:

因此,实际上,我希望添加两个行日期之间存在的间隔。如果一行的结束日期与下一行的开始日期之间存在差距,我希望能够在它们之间插入具有相同项目的行并存储中间日期和销售量0

我正在尝试在 Google BigQuery 控制台中执行此操作。

【问题讨论】:

  • 您真的在使用 BigQuery 吗?您接受了无法在 BigQuery 中运行的答案,因此可能会误导其他寻找类似用例的用户!
  • 我真的在使用 BigQuery。我不得不问你认为我可以通过提出一个有需要的问题,然后接受一个没有真正满足我需要的答案来获得什么?不,当我使用 dateadd 时它不起作用,但是当我使用 date_add 时它确实起作用。除此之外,它绝对可以满足我的需要,而且我现在正在使用它。我来这里是为了问另一个问题,这个问题是建立在我使用这个之上的。我就是这样发现你的评论的。

标签: sql google-bigquery sql-insert where-clause window-functions


【解决方案1】:

您可以使用union alllead()

select item, store, start, end, sold
from t
union all
select item, store, dateadd(end, interval 1 day), dateadd(next_start, interval -1 day)
from (select item, store, end, lead(start) over (partition item, store start) as next_start
      from t
     ) t
where next_start  dateadd(end, interval 1 day);

【讨论】:

  • 谢谢。我通常不需要执行这种类型的功能,但这让我想起了使用 UNION ALL 来处理这种类型的事情。我很感激。我得看看你的书!
【解决方案2】:

您可以使用窗口函数和insert ... select 语法来创建“缺失”行:

insert into mytable (item, store, start, end, sold)
select 
    item,
    store, 
    dateadd(end, interval 1 day),
    dateadd(lead_start, interval -1 day),
     0
from (
    select 
        t.*,
        lead(start) over(partition by item, store order by start) lead_start
    from mytable t
) t
where lead_start > dateadd(end, interval 1 day)

【讨论】:

  • 我没有使用这个只是因为我在尝试解决我的问题时选择了第一个答案,但是仔细考虑一下,我觉得这对我的问题同样有效。甚至没有想到要这样做,它使用相同的功能。一个 6 个,另一个六个。
【解决方案3】:

以下是 BigQuery 标准 SQL

#standardSQL
SELECT * FROM `project.dataset.table` UNION ALL
SELECT * FROM (
  SELECT item, store,
    DATE_ADD(`end`, INTERVAL 1 DAY) new_start,
    DATE_SUB(LEAD(start) OVER(PARTITION BY item, store ORDER BY start), INTERVAL 1 DAY) new_end, 0
  FROM `project.dataset.table` 
)
WHERE new_start <= new_end

如果应用于您问题中的样本数据 - 输出是

Row item    store   start       end         sold     
1   5       1       2020-01-01  2020-01-15  22   
2   5       1       2020-01-16  2020-01-31  0    
3   5       1       2020-02-01  2020-02-20  14      

如果你想将那些“缺失”的行插入到你的表中 - 你应该只使用第二个选择 - 这是

INSERT INTO `project.dataset.table`
SELECT * FROM (
  SELECT item, store,
    DATE_ADD(`end`, INTERVAL 1 DAY) new_start,
    DATE_SUB(LEAD(start) OVER(PARTITION BY item, store ORDER BY start), INTERVAL 1 DAY) new_end, 0
  FROM `project.dataset.table` 
)
WHERE new_start <= new_end 

【讨论】:

  • 与我对下一个答案的评论相同;我也可以看到这是如何工作的,但是我选择了答案作为我选择首先尝试的答案(这是第一个响应)。也感谢您留下答案!
  • 这不是关于谁先!更多的是正确的答案,以及比其他人最好或更好的答案!但至少是正确的!显然,这取决于您要接受什么答案 - 但您误导了其他正在寻找类似用例的用户
  • 好吧,我想我没有资格回答什么是最好的。我的评论的意思是我看到你的评论是正确的,但第一个答案也是正确的。他们俩都会解决我的问题。因此,我将就我应该如何决定什么是最好的进行输入。鉴于我的 SQL 新手级别,我不知道我怎么能说出这里给出的答案中的哪个比另一个更好。
  • 当然。别担心 :o) 你做的一切都是正确的 :o) 接受和投票等等真的取决于你。
猜你喜欢
  • 2021-10-02
  • 2011-03-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-02
  • 1970-01-01
相关资源
最近更新 更多