【问题标题】:Oracle 18c - Complex sqlOracle 18c - 复杂的 sql
【发布时间】:2020-03-06 23:11:24
【问题描述】:

我有一个包含以下列的表格:

Emp_ID Number
Emp_flag Varchar2(1)
Date_1 Date
Date_2 Date
create_date Date

此表没有PK,Emp_id重复的记录很多..

我需要知道的是,当输入一个新的Date_1 时(因此空到某个日期,或从日期 1 到日期 2)发生在什么日期。

我不能只看一条记录来比较 Date_1 和 create_date,因为在给定 Emp_ID 的许多记录中,当 Date_1 简单地“复制”到新记录时,有很多次。 Date_1 可能最初是在 2019 年 2 月 15 日输入的,其值为 02/01/2019。现在假设 Date_2 于 2020 年 2 月 12 日添加。所以表格看起来像这样:

Emp_ID  Emp_flag    Date_1     Date_2      Create_Date
123     Y           Null       Null        1/18/2018
123     Y           02/1/2019  Null        02/15/2019
123     Y           02/1/2019  02/12/2021  02/12/2020

我需要一个 SQL 查询,它会告诉我 Emp_ID 123 在 2019 年 2 月 15 日输入了 02/1/2019 的 Date_1,并且不会获取任何其他记录。

预期输出:

Emp_ID  Emp_flag    Date_1     Date_2      Create_Date
123     Y           02/1/2019  Null        02/15/2019

示例 2(注意 date_1 不同):

Emp_ID  Emp_flag    Date_1     Date_2      Create_Date
456     Y           Null       Null        1/18/2018
456     Y           10/1/2019  Null        02/15/2019
456     Y           11/2/2019  02/12/2021  02/12/2020

预期输出:

Emp_ID  Emp_flag    Date_1     Date_2      Create_Date
456     Y           10/1/2019  Null        02/15/2019
456     Y           11/2/2019  02/12/2021  02/12/2020

示例 3:

Emp_ID  Emp_flag    Date_1     Date_2      Create_Date
456     Y           Null       Null        1/18/2018
456     Y           10/1/2019  Null        02/15/2019
456     Y           10/1/2019  Null        02/15/2019
456     Y           11/2/2019  02/12/2021  02/12/2020

预期输出:

Emp_ID  Emp_flag    Date_1     Date_2      Create_Date
456     Y           10/1/2019  Null        02/15/2019
456     Y           11/2/2019  02/12/2021  02/12/2020

示例 4:

Emp_ID  Emp_flag    Date_1     Date_2      Create_Date
456     Y           10/1/2019  Null        02/15/2019
456     Y           10/1/2019  Null        02/16/2019

预期输出:无记录。

【问题讨论】:

  • 行是否会更新,或者是否会为每次数据更改创建一个新行?
  • 没有更新。每次数据更改都会创建一个新的。
  • 不完全确定我理解这个问题。您能否更详细地解释所需的标准和预期的输出
  • 请查看添加的示例/预期结果

标签: sql oracle oracle18c


【解决方案1】:

您可以使用Lag函数检查date_1之前的值是否存在。

SELECT x.emp_id,
       x.date_1,
       x.create_date AS first_date_with_date_1
FROM (
    SELECT t.emp_id,
           t.create_date,
           t.date_1,
           LAG(t.date_1) OVER (PARTITION BY t.emp_id ORDER BY t.create_date) AS last_date_1
    FROM your_table t
) x
WHERE x.date_1 IS NOT NULL
  AND x.last_date_1 IS NULL

【讨论】:

  • 如果您正在寻找对date_1 的更改,而不仅仅是插入,那么最后一个WHERE 条件将只是AND x.last_date_1 <> x.date_1
  • 我认为这行不通,请查看我的更新 - 添加了预期结果和一个新示例。
  • @user3224907 如果您正在寻找任何更改,而不仅仅是添加,只需按照 EricBrandt 在上面评论中的建议进行操作
  • 当有多个具有相同 Date_1 的记录时,这不起作用。请问可以更新帐号吗?此外,如果所有记录的 Date_1 相同,则不要输出此 Emp_id。
【解决方案2】:

测试所有情况:

with t(emp_id, emp_flag, date_1, date_2, create_date) as (
    select 101, 'Y', null,              null,              date '2018-01-18' from dual union all
    select 101, 'Y', date '2019-02-01', null,              date '2019-02-15' from dual union all
    select 101, 'Y', date '2019-02-01', date '2021-02-12', date '2019-02-16' from dual union all
    select 102, 'Y', null,              null,              date '2018-01-18' from dual union all
    select 102, 'Y', date '2019-02-10', null,              date '2019-02-15' from dual union all
    select 102, 'Y', date '2019-02-11', date '2021-02-12', date '2019-02-16' from dual union all
    select 103, 'Y', null,              null,              date '2018-01-18' from dual union all
    select 103, 'Y', date '2019-02-10', null,              date '2019-02-15' from dual union all
    select 103, 'Y', date '2019-02-10', null,              date '2019-02-15' from dual union all
    select 103, 'Y', date '2019-02-11', date '2021-02-21', date '2020-12-02' from dual )
select emp_id, emp_flag, date_1, date_2, create_date
  from (
    select emp_ID, emp_flag, date_1, date_2, create_date,
           lag(date_1) over (partition by emp_id order by create_date) prev_dt1
      from t )
  where date_1 <> nvl(prev_dt1, date_1 - 1);

结果:

    EMP_ID EMP_FLAG DATE_1      DATE_2      CREATE_DATE
---------- -------- ----------- ----------- -----------
       101 Y        2019-02-01              2019-02-15
       102 Y        2019-02-10              2019-02-15
       102 Y        2019-02-11  2021-02-12  2019-02-16
       103 Y        2019-02-10              2019-02-15
       103 Y        2019-02-11  2021-02-21  2020-12-02

编辑:

当 Date_1 中有多个记录没有变化时。它 不应返回该 Emp_id 的记录

在这种情况下,date_1 设置在第一行(id 104)。如果您想在这种情况下隐藏行,请使用:

with t(emp_id, emp_flag, date_1, date_2, create_date) as (
    select 104, 'Y', date '2019-02-10', null,              date '2019-02-15' from dual union all
    select 104, 'Y', date '2019-02-10', null,              date '2019-02-16' from dual union all
    select 105, 'Y', date '2019-02-10', null,              date '2019-02-15' from dual union all
    select 105, 'Y', null,              null,              date '2019-02-16' from dual )
select emp_id, emp_flag, date_1, date_2, create_date
  from (
    select emp_ID, emp_flag, date_1, date_2, create_date,
           lag(date_1) over (partition by emp_id order by create_date) prev_dt1, 
           row_number() over (partition by emp_id order by create_date) rn
      from t )
  where (date_1 is not null and prev_dt1 is null and rn > 1)
     or date_1 <> prev_dt1
     or date_1 is null and prev_dt1 is not null;

我还添加了前一个日期设置为空(id 105)的情况。如果不可能或您不想要它,请删除最后一行。

【讨论】:

  • 当 Date_1 中有多个没有变化的记录时,这似乎不起作用。它不应该返回该 Emp_id 的记录,但确实如此。
【解决方案3】:

您可以在这里使用滞后功能代替超前:

with tableA as
(
select 456 as Emp_ID,'Y' as Emp_flag,CAST(NUll as date) as Date_1,CAST(NULL as date) as Date_2,CAST('18Jan2018' as date) as Create_date from dual union
select 456,'Y',CAST('01Oct2019' as date),Null,CAST('15Feb2019' as date) from dual union
select 456,'Y',CAST('02Nov2019' as date),CAST('12Feb2021' as date),CAST('12Feb2020' as date) from dual) 

select x.Emp_ID,x.Emp_flag,x.Date_1,x.Date_2,x.Create_date
from
(select a.*
       ,lag(a.date_1) Over (partition by a.Emp_ID order by a.create_date) as lag_date
from tableA a) x
where x.date_1 is not null and x.date_1<>COALESCE(x.lag_date,CAST('01Jan2100' as date))

这只会在 date_1 发生变化时给出值。由于 NULL 比较不起作用,我已将它们替换为 2100 年 1 月 1 日。希望这会有所帮助。

编辑:

我检查了您提到的样本,它似乎确实有效。如果它不起作用,请分享您得到的预期和结果:

with tableA as
(
select 456 as Emp_ID,'Y' as Emp_flag,CAST(NUll as date) as Date_1,CAST(NULL as date) as Date_2,CAST('18Jan2018' as date) as Create_date from dual union
select 456,'Y',CAST('01Oct2019' as date),Null,CAST('15Feb2019' as date) from dual union
select 456,'Y',CAST('01Oct2019' as date),CAST('12Feb2021' as date),CAST('12Feb2020' as date) from dual) 

select x.Emp_ID,x.Emp_flag,x.Date_1,x.Date_2,x.Create_date
from
(select a.*
       ,lag(a.date_1) Over (partition by a.Emp_ID order by a.create_date) as lag_date
from tableA a) x
where x.date_1 is not null and x.date_1<>COALESCE(x.lag_date,CAST('01Jan2100' as date))

【讨论】:

  • 当 Date_1 中有多个没有变化的记录时,这似乎不起作用。它不应该返回该 Emp_id 的记录,但确实如此。
  • 为您提到的示例添加了编辑...似乎工作正常
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-01-14
  • 1970-01-01
  • 2016-01-22
  • 2019-04-18
  • 1970-01-01
  • 2020-10-05
相关资源
最近更新 更多