【问题标题】:How to get the closest dates in Oracle sql如何在 Oracle sql 中获取最近的日期
【发布时间】:2012-12-05 10:16:18
【问题描述】:

例如,我有 2 个时间表: T1

id time
1 18:12:02
2 18:46:57
3 17:49:44
4 12:19:24
5 11:00:01
6 17:12:45

和T2

id time
1 18:13:02
2 17:46:57

我需要从 T1 获取最接近 T2 时间的时间。这些表之间没有关系。 应该是这样的:

select T1.calldatetime
from T1, T2 
where T1.calldatetime between 
T2.calldatetime-(
    select MIN(ABS(T2.calldatetime-T1.calldatetime))
    from T2, T1)
and
T2.calldatetime+(
    select MIN(ABS(T2.calldatetime-T1.calldatetime))
    from T2, T1)

但我无法得到它。有什么建议吗?

【问题讨论】:

    标签: sql oracle date-arithmetic


    【解决方案1】:

    您只需使用单个笛卡尔连接即可解决您的问题,这与其他使用多个连接的解决方案不同。我假设时间存储为 VARCHAR2。如果它存储为日期,那么您可以删除 TO_DATE 函数。如果它被存储为日期(我强烈推荐这个),你将不得不删除日期部分

    我已经让它稍微冗长了,所以很明显发生了什么。

    select *
      from ( select id, tm
                  , rank() over ( partition by t2id order by difference asc ) as rnk
               from ( select t1.*, t2.id as t2id
                           , abs( to_date(t1.tm, 'hh24:mi:ss') 
                                  - to_date(t2.tm, 'hh24:mi:ss')) as difference
                        from t1
                       cross join t2
                             ) a
                     )
     where rnk = 1
    

    基本上,这会计算出 T1 和 T2 中每次之间的绝对差值,然后选择 T2 ID 中的最小差值;从 T1 返回数据。

    这里是SQL Fiddle format

    不太漂亮(但更短)的格式是:

    select *
      from ( select t1.*
                  , rank() over ( partition by t2.id 
                                      order by abs(to_date(t1.tm, 'hh24:mi:ss') 
                                                - to_date(t2.tm, 'hh24:mi:ss'))
                                      ) as rnk
               from t1
              cross join t2
                    ) a
     where rnk = 1
    

    【讨论】:

      【解决方案2】:

      我相信这是您要查找的查询:

      CREATE TABLE t1(id INTEGER, time DATE);
      CREATE TABLE t2(id INTEGER, time DATE);
      
      INSERT INTO t1 VALUES (1, TO_DATE ('18:12:02', 'HH24:MI:SS'));
      INSERT INTO t1 VALUES (2, TO_DATE ('18:46:57', 'HH24:MI:SS'));
      INSERT INTO t1 VALUES (3, TO_DATE ('17:49:44', 'HH24:MI:SS'));
      INSERT INTO t1 VALUES (4, TO_DATE ('12:19:24', 'HH24:MI:SS'));
      INSERT INTO t1 VALUES (5, TO_DATE ('11:00:01', 'HH24:MI:SS'));
      INSERT INTO t1 VALUES (6, TO_DATE ('17:12:45', 'HH24:MI:SS'));
      
      INSERT INTO t2 VALUES (1, TO_DATE ('18:13:02', 'HH24:MI:SS'));
      INSERT INTO t2 VALUES (2, TO_DATE ('17:46:57', 'HH24:MI:SS'));
      
      SELECT t1.*, t2.*
        FROM t1, t2,
             (  SELECT t2.id, MIN (ABS (t2.time - t1.time)) diff
                  FROM t1, t2
              GROUP BY t2.id) b
       WHERE ABS (t2.time - t1.time) = b.diff;
      

      确保时间列具有相同的日期部分,否则 t2.time - t1.time 部分将不起作用。

      编辑:感谢您的接受,但 Ben 在下面的回答更好。它使用 Oracle 分析功能,性能会更好。

      【讨论】:

        【解决方案3】:

        这里从 T1 中选择与 T2 中的任何一个距离最小的行:

        select T1.id, T1.calldatetime from T1, T2 
         where ABS(T2.calldatetime-T1.calldatetime)
                 =( select MIN(ABS(T2.calldatetime-T1.calldatetime))from T1, T2);
        

        (用mysql测试过,希望你不要从中得到ORA)

        编辑:根据最后的评论,应该是这样的:

        drop table t1;
        drop table t2;
        create table t1(id int, t time);
        create table t2(id int, t time);
        
        insert into t1 values (1, '18:12:02');
        insert into t1 values (2, '18:46:57');
        insert into t1 values (3, '17:49:44');
        insert into t1 values (4, '12:19:24');
        insert into t1 values (5, '11:00:01');
        insert into t1 values (6, '17:12:45');
        
        insert into t2 values (1, '18:13:02');
        insert into t2 values (2, '17:46:57');
        
        select ot2.id, ot2.t, ot1.id, ot1.t from t2 ot2, t1 ot1  
         where ABS(ot2.t-ot1.t)=
               (select min(abs(t2.t-t1.t)) from t1, t2 where t2.id=ot2.id)
        

        生产:

        id      t       id      t
        1       18:13:02        1       18:12:02
        2       17:46:57        3       17:49:44
        

        【讨论】:

        • 这个找到了 T2.calldatetime-T1.calldatetime 之间的最小差异,而不是只获得 T1.calldatetime 的一行,这与我需要的不同。我需要所有行中最小的。
        • 嗯。所以你想要 T1 中的每一行与 T2 中差异最小的行?还是对于 T2 中的每一行 T1 中的最小差异?
        • 对于 T2 中的每一行,T1 中的最小差异
        【解决方案4】:

        另一种使用分析函数的方法。 可能很奇怪:)

        select id, time,
        case 
          when to_date(time, 'hh24:mi:ss') - to_date(lag_time, 'hh24:mi:ss') < to_date(lead_time, 'hh24:mi:ss') - to_date(time, 'hh24:mi:ss')
            then lag_time 
            else lead_time
          end closest_time
        from (
        select id, tbl,
          LAG(time, 1, null) OVER (ORDER BY time) lag_time, 
          time,
          LEAD(time, 1, null) OVER (ORDER BY time) lead_time 
        from
          (
          select id, time, 1 tbl from t1
          union all
          select id, time, 2 tbl from t2
          )
        )
        where tbl = 2
        

        SQLFiddle...及以后!

        【讨论】:

          【解决方案5】:

          试试这个查询有点长,我会尽量优化它

          select * from t1
          where id in (
          select id1 from 
          (select id1,id2,
          rank()  over (partition by id2 order by diff) rnk
          from
          (select distinct t1.id id1,t2.id id2,
          round(min(abs(to_date(t1.time,'HH24:MI:SS') - to_date(t2.time,'HH24:MI:SS'))),2) diff 
          from 
          t1,t2
          group by t1.id,t2.id) )
          where rnk = 1);
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2019-05-22
            • 1970-01-01
            • 2022-11-22
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多