SQL LAG() 函数与带有条件的情况

huangapple go评论139阅读模式
英文:

SQL LAG() function with condition where

问题

我有我的表格如下:

  1. WITH
  2. my_table (user_id, date, event_name, value) AS (
  3. VALUES
  4. (1,'2021-10-01', 'level', 5),
  5. (1,'2021-10-03', 'purchase', null),
  6. (1,'2021-10-05', 'purchase', null),
  7. (2,'2021-10-02', 'level', 10),
  8. (2,'2021-10-03', 'purchase', null)
  9. )
  10. SELECT *
  11. FROM my_table

我只想为每个user_id的每次purchase之前添加一个列,显示最后一次level的值。期望的表格应如下所示:

  1. |user_id|date |event_name|value|level_achieved|
  2. |-------|----------|----------|-----|--------------|
  3. |1 |2021-10-01|level |5 | |
  4. |1 |2021-10-03|purchase |null |5 |
  5. |1 |2021-10-05|purchase |null |5 |
  6. |2 |2021-10-02|level |10 | |
  7. |2 |2021-10-03|purchase |null |10 |

感谢您的帮助!

英文:

I have my table like this:

  1. WITH
  2. my_table (user_id, date, event_name, value) AS (
  3. values
  4. (1,'2021-10-01', 'level', 5),
  5. (1,'2021-10-03', 'purchase', null),
  6. (1,'2021-10-05', 'purchase', null),
  7. (2,'2021-10-02', 'level', 10),
  8. (2,'2021-10-03', 'purchase', null)
  9. )
  10. SELECT *
  11. FROM my_table
user_id date event_name level
1 2021-10-01 level 5
1 2021-10-03 purchase
1 2021-10-05 purchase
2 2021-10-02 level 10
2 2021-10-03 purchase

All I want is to add column with the last level achieved before every purchase for every user_id.
Desired table should look like this

user_id date event_name level level_achieved
1 2021-10-01 level 5
1 2021-10-03 purchase 5
1 2021-10-05 purchase 5
2 2021-10-02 level 10
2 2021-10-03 purchase 10

Thanks for helping me!

答案1

得分: 3

假设级别不会下降,您可以只使用 max,它将忽略 null 值:

  1. SELECT *,
  2. if(value is null, max(value) over(partition by user_id order by date)) level_achieved
  3. FROM my_table;

输出:

user_id date event_name value level_achieved
1 2021-10-01 level 5 NULL
1 2021-10-03 purchase NULL 5
1 2021-10-05 purchase NULL 5
2 2021-10-02 level 10 NULL
2 2021-10-03 purchase NULL 10

或者使用带有 ignore nulls 选项的 last_value

  1. SELECT *,
  2. if(value is null, last_value(value) IGNORE NULLS over(partition by user_id order by date)) level_achieved
  3. FROM my_table;
英文:

Assuming that level can't go down you can use just max which will ignore null's:

  1. SELECT *,
  2. if(value is null, max(value) over(partition by user_id order by date)) level_achieved
  3. FROM my_table;

Output:

user_id date event_name value level_achieved
1 2021-10-01 level 5 NULL
1 2021-10-03 purchase NULL 5
1 2021-10-05 purchase NULL 5
2 2021-10-02 level 10 NULL
2 2021-10-03 purchase NULL 10

Or using last_value with ignore nulls option:

  1. SELECT *,
  2. if(value is null, last_value(value) IGNORE NULLS over(partition by user_id order by date)) level_achieved
  3. FROM my_table;

答案2

得分: 1

我建议您创建一个包含以下内容的子查询:

  1. user_idleveldate as date_startlead(date) over(partition by user_id order by date asc) as date_end
  2. (其中 level 不为 null

您将获得以下结构:

  1. user_idleveldate_startdate_end

接下来,您可以与以下内容进行连接:

  1. my_table ON my_table.date >= sub_query.date_start
  2. AND my_table.date < sub_query.date_end
  3. AND my_table.user_id = sub_query.user_id

这样,您可以轻松获取特定日期范围的级别。

祝您好运。

英文:

I would advise you to create a subquery with the following:

  1. user_id, level, date as date_start, lead(date) over(partition by user_id order by date asc) as date_end
  2. (where level is not null)

You will get a structure like:

  1. user_id, level, date_start, date_end

Next you can join with:

  1. my_table ON my_table.date &gt;= sub_query.date_start
  2. AND my_table.date &lt; sub_query.date_end
  3. AND my_table.user_id = sub_query.user_id

With this you can easily get the level for that specific date range.

Good luck

huangapple
  • 本文由 发表于 2023年8月5日 01:41:13
  • 转载请务必保留本文链接:https://go.coder-hub.com/76838119.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定