【问题标题】:Oracle sql compare rows within table / data set dynamicallyOracle sql动态比较表/数据集中的行
【发布时间】:2021-04-29 10:09:39
【问题描述】:

以下问题:

我想比较表中的行。

假设我有一个包含以下数据星座的测试用例表:

ID  Result  Date

123 success 29.04.2021
123 error   28.04.2021
123 success 27.04.2021
123 success 26.04.2021
123 error   25.04.2021

234 success 29.04.2021
234 success 28.04.2021
234 success 27.04.2021
234 success 26.04.2021
234 error   25.04.2021

我希望我的查询仅返回过去 3 天结果相同的那些 ID。 但我想在不使用 PL/SQL 的情况下动态处理 days 参数。 这意味着 - 如果我需要比较过去 5 天,我只想更改我的 sql 语句中的参数。 能实现吗?

回到我上面的例子:

我希望我的查询回馈:

ID
234

最好的问候

【问题讨论】:

  • 如果您没有 '28.04.2021' 怎么办 - 您应该查询分析 26、27、29 吗?还是只有 27 和 29? “过去 3 天”到底是什么意思?只是 >=today-3 天?
  • @SayanMalakshinov 我想检查从今天开始的最后 3 天。如果我只有两个条目,那么我只想比较两个条目...
  • 好的,请看我更新的答案

标签: sql oracle compare rows


【解决方案1】:

您可以使用简单的group by + having 子句:

select id
from t
where dt>=sysdate-3
group by id
having count(distinct result)=1 -- just one distinct `result`
and count(*)=3 -- only 3 rows >= sysdate-3
and count(distinct dt)=3 -- all 3 days are present;

带有测试数据的完整测试演员:

with t(ID, Result, Dt) as (
select 123, 'success' , to_date('29.04.2021','dd.mm.yyyy') from dual union all
select 123, 'error  ' , to_date('28.04.2021','dd.mm.yyyy') from dual union all
select 123, 'success' , to_date('27.04.2021','dd.mm.yyyy') from dual union all
select 123, 'success' , to_date('26.04.2021','dd.mm.yyyy') from dual union all
select 123, 'error  ' , to_date('25.04.2021','dd.mm.yyyy') from dual union all
select 234, 'success' , to_date('29.04.2021','dd.mm.yyyy') from dual union all
select 234, 'success' , to_date('28.04.2021','dd.mm.yyyy') from dual union all
select 234, 'success' , to_date('27.04.2021','dd.mm.yyyy') from dual union all
select 234, 'success' , to_date('26.04.2021','dd.mm.yyyy') from dual union all
select 234, 'error  ' , to_date('25.04.2021','dd.mm.yyyy') from dual
)
select id
from t
where dt>=sysdate-3
group by id
having count(distinct result)=1 -- just one distinct `result`
and count(*)=3 -- only 3 rows >= sysdate-3
and count(distinct dt)=3 -- all 3 days are present
;

结果:

        ID
----------
       234

根据上述评论中的说明修改查询:

我想检查从今天开始的最后 3 天。如果我只有两个条目,那么我只想比较两个条目...

select id
from t
where dt>=sysdate-3
group by id
having count(distinct result)=1 -- just one distinct `result`
;

完整的测试用例:

with t(ID, Result, Dt) as (
select 123, 'success' , to_date('29.04.2021','dd.mm.yyyy') from dual union all
select 123, 'error  ' , to_date('28.04.2021','dd.mm.yyyy') from dual union all
select 123, 'success' , to_date('27.04.2021','dd.mm.yyyy') from dual union all
select 123, 'success' , to_date('26.04.2021','dd.mm.yyyy') from dual union all
select 123, 'error  ' , to_date('25.04.2021','dd.mm.yyyy') from dual union all
select 234, 'success' , to_date('29.04.2021','dd.mm.yyyy') from dual union all
select 234, 'success' , to_date('28.04.2021','dd.mm.yyyy') from dual union all
select 234, 'success' , to_date('27.04.2021','dd.mm.yyyy') from dual union all
select 234, 'success' , to_date('26.04.2021','dd.mm.yyyy') from dual union all
select 234, 'error  ' , to_date('25.04.2021','dd.mm.yyyy') from dual
)
select id
from t
where dt>=sysdate-3
group by id
having count(distinct result)=1 -- just one distinct `result`
;
----------------------
--Results:

        ID
----------
       234

附言。最好以这种格式给出测试数据:

with t(ID, Result, Dt) as (
select 123, 'success' , to_date('29.04.2021','dd.mm.yyyy') from dual union all
select 123, 'error  ' , to_date('28.04.2021','dd.mm.yyyy') from dual union all
select 123, 'success' , to_date('27.04.2021','dd.mm.yyyy') from dual union all
select 123, 'success' , to_date('26.04.2021','dd.mm.yyyy') from dual union all
select 123, 'error  ' , to_date('25.04.2021','dd.mm.yyyy') from dual union all
select 234, 'success' , to_date('29.04.2021','dd.mm.yyyy') from dual union all
select 234, 'success' , to_date('28.04.2021','dd.mm.yyyy') from dual union all
select 234, 'success' , to_date('27.04.2021','dd.mm.yyyy') from dual union all
select 234, 'success' , to_date('26.04.2021','dd.mm.yyyy') from dual union all
select 234, 'error  ' , to_date('25.04.2021','dd.mm.yyyy') from dual
)
select *
from t;

【讨论】:

    【解决方案2】:

    从 Oracle 12c 开始,您可以使用MATCH_RECOGNIZE:

    SELECT id
    FROM   table_name
    MATCH_RECOGNIZE (
      PARTITION BY id
      ORDER BY "DATE"
      ONE ROW PER MATCH
      PATTERN ( same{3} $ )
      DEFINE same AS FIRST( result ) = result
    )
    

    或者,在早期版本中,您可以使用:

    SELECT id
    FROM   (
      SELECT id,
             ROW_NUMBER() OVER ( PARTITION BY id ORDER BY "DATE" DESC )
               AS id_rn,
             ROW_NUMBER() OVER ( PARTITION BY id, result ORDER BY "DATE" DESC )
               AS result_rn
      FROM   table_name
    )
    WHERE id_rn = 3
    AND   result_rn = 3
    

    其中,对于样本数据:

    CREATE TABLE table_name ( ID, Result, "DATE" ) AS
    SELECT 123, 'success', DATE '2021-04-29' FROM DUAL UNION ALL
    SELECT 123, 'error',   DATE '2021-04-28' FROM DUAL UNION ALL
    SELECT 123, 'success', DATE '2021-04-27' FROM DUAL UNION ALL
    SELECT 123, 'success', DATE '2021-04-26' FROM DUAL UNION ALL
    SELECT 123, 'error',   DATE '2021-04-25' FROM DUAL UNION ALL
    SELECT 234, 'success', DATE '2021-04-29' FROM DUAL UNION ALL
    SELECT 234, 'success', DATE '2021-04-28' FROM DUAL UNION ALL
    SELECT 234, 'success', DATE '2021-04-27' FROM DUAL UNION ALL
    SELECT 234, 'success', DATE '2021-04-26' FROM DUAL UNION ALL
    SELECT 234, 'error',   DATE '2021-04-25' FROM DUAL;
    

    输出:

    ID
    234

    db小提琴here

    【讨论】:

      【解决方案3】:

      假设您每天每个 id 有一行,那么您可以使用lag():

      select t.*
      from (select t.*,
                   lag(result, 2) over (partition by id order by date) as date_2,
                   lag(result, 2) over (partition by id, result order by date) as date_result_2
            from t
           ) t
      where date_2 = date_result_2;
      

      这将返回前两行(假设每天每个 id 有一行)具有相同结果的所有行。

      您可以在您关心的时间范围内添加过滤器。这可能应该在外部查询中。

      这样做是看过去两行,但有两种不同的方式:

      • 每个id 一次。
      • 每个id 和result 一次

      如果它们相同,则后面两行的结果相同,中间的行也一样。

      【讨论】:

        猜你喜欢
        • 2011-08-31
        • 2018-10-20
        • 1970-01-01
        • 2015-04-03
        • 1970-01-01
        • 2020-08-12
        • 1970-01-01
        • 2016-12-08
        • 1970-01-01
        相关资源
        最近更新 更多