【发布时间】:2022-02-03 09:34:13
【问题描述】:
问题: 我有一个交易表(见下文),其中包含日期格式的(打开/开始)或(关闭/结束)交易。任务是将这些交易与其相应的日期合并,但是,也可能存在交易已打开/开始但未关闭/结束的情况,在这种情况下,只需显示开始日期,并分配标志“Y” .其余有结束日期的情况,标志将为“N”。我已经能够根据 first_value(Flag IGNORE NULLS) over(按 Customer_ID 顺序按 EndDate desc 进行分区) 的值设置一个标志,但是我很难将开始日期与结束日期匹配。
逻辑:
- 一天可以有多个开始和结束日期,只有时差。
- 每位客户每天只能进行一次开始和结束日期交易。
- 每个客户每天只能有一个开始日期(打开)交易。
- 标记“N”仅用于已关闭的交易,“Y”用于打开,即没有结束日期。
当前设置示例如下所示: 注意:对于这个特定的客户,我们有相同数量的交易(插入和删除,所以我知道标志将是'N',当我们映射开始和结束日期时,但是当开始日期多于结束日期时,解决方案也必须工作其他客户,其中最终(最新)开始日期行的标志为“Y”。
| Customer_Id | Start Date | End Date | Flag |
|---|---|---|---|
| 111 | 02/07/2020 20:58:32.000000 | N | |
| 111 | 02/07/2020 19:18:04.000000 | N | |
| 111 | 01/06/2020 09:38:49.000000 | N | |
| 111 | 01/06/2020 09:36:34.000000 | N | |
| 111 | 29/05/2020 16:58:07.000000 | N | |
| 111 | 02/07/2020 20:57:52.000000 | N | |
| 111 | 02/07/2020 19:17:22.000000 | N | |
| 111 | 29/05/2020 16:58:06.000000 | N | |
| 111 | 01/06/2020 09:38:40.000000 | N | |
| 111 | 01/06/2020 09:36:34.000000 | N |
预期结果:
| Customer_Id | Start Date | End Date | Flag |
|---|---|---|---|
| 111 | 02/07/2020 20:57:52.000000 | 02/07/2020 20:58:32.000000 | N |
| 111 | 02/07/2020 19:17:22.000000 | 02/07/2020 19:18:04.000000 | N |
| 111 | 01/06/2020 09:38:40.000000 | 01/06/2020 09:38:49.000000 | N |
| 111 | 01/06/2020 09:36:34.00000 | 01/06/2020 09:36:34.000000 | N |
| 111 | 29/05/2020 16:58:06.000000 | 29/05/2020 16:58:07.000000 | N |
适用于上述示例的部分解决方案:
select customer_id
,start_date
,lead(end_date) -- find the next row's end date
over (partition by customer_id
order by coalesce(start_date, end_date)) as new_end
,case when new_end is null then 'Y' else 'N' end as flag
from tab
qualify start_date is not null -- only return starting rows
order by 1,2;
但是,如果开始日期多于结束日期(例如,几个已关闭的交易,一个打开的交易(不仅可以是最新/最新的,还可以是中间的某个地方..)),它将不起作用。例如。如果交易未完成:开始日期 12/01/2019 09:36:34.00000 但没有结束日期 然后 lead() 跳过这个 null enddate 值并分配下一个可用的结束日期,使解决方案看起来像这样:
| Customer_Id | Start Date | End Date | Flag |
|---|---|---|---|
| 111 | 02/07/2020 20:57:52.000000 | 02/07/2020 20:58:32.000000 | N |
| 111 | 02/07/2020 19:17:22.000000 | 02/07/2020 19:18:04.000000 | N |
| 111 | 01/06/2020 09:38:40.000000 | 01/06/2020 09:38:49.000000 | N |
| 111 | 12/01/2019 09:36:34.00000 | 18/11/2019 16:58:07.000000 | N |
| 111 | 18/11/2019 16:58:06.000000 | NULL | NULL |
什么时候应该是这样的:
| Customer_Id | Start Date | End Date | Flag |
|---|---|---|---|
| 111 | 02/07/2020 20:57:52.000000 | 02/07/2020 20:58:32.000000 | N |
| 111 | 02/07/2020 19:17:22.000000 | 02/07/2020 19:18:04.000000 | N |
| 111 | 01/06/2020 09:38:40.000000 | 01/06/2020 09:38:49.000000 | N |
| 111 | 12/01/2019 09:36:34.00000 | NULL | Y |
| 111 | 18/11/2019 16:58:06.000000 | 18/11/2019 16:58:07.000000 | N |
如何找到适合这两种情况的解决方案?
【问题讨论】:
-
您想匹配 DATE 和 TIMESTAMP?您的预期结果是什么,为什么?
-
将两者都更改为时间戳,添加预期结果。预期结果的原因 - 所有交易都需要输入一行,并带有一个标志。
-
结果与数据不匹配,NULL和上一行将被切换。
-
它确实如此,这正是我在尝试对一个缺失的结束日期应用相同逻辑时得到的结果(这种情况下缺失的一个将是第 4 行(与 01/06/2020 09:36 无关) :34,但脚本会跳过这条缺失的记录并导入下一条 (29/05..)
-
这个结果是不可能的,29/05/2020 早于 01/06/2020。一定是别的东西。顺便说一句,如果您的开始日期和结束日期具有完全相同的时间戳,则可能需要添加逻辑首先要排序的内容,例如
order by coalesce(start_date, end_date), start_date nulls first)