Sql 如何选择两个日期相差超过40分钟的记录?最好用甲骨文

Sql 如何选择两个日期相差超过40分钟的记录?最好用甲骨文,sql,oracle,date,Sql,Oracle,Date,我必须选择当天的日志记录,其中执行开始日期和结束日期之间的差异超过40分钟 select * from iwdata.IW_MASTER_LOG WHERE TRUNC(EXECUTION_START_DATE)=TRUNC(SYSDATE) AND (EXECUTION_START_DATE-EXECUTION_ENDED_DATE) >to_date('40','mi'); 但是这个查询给了我一个错误 ORA-00932:不一致的数据类型:预期的数字获取日期 with a as

我必须选择当天的日志记录,其中执行开始日期和结束日期之间的差异超过40分钟

select * from iwdata.IW_MASTER_LOG
WHERE TRUNC(EXECUTION_START_DATE)=TRUNC(SYSDATE)  
AND (EXECUTION_START_DATE-EXECUTION_ENDED_DATE) >to_date('40','mi');
但是这个查询给了我一个错误

ORA-00932:不一致的数据类型:预期的数字获取日期

with a as ( select sysdate sd, sysdate+(1/24/60)*39 ed from dual)
-- in with sysdate and sysdate + 39 minute
select to_char(sd,'dd.mm.yyyy hh24:mi:ss'),
       to_char(ed,'dd.mm.yyyy hh24:mi:ss'), 
       to_number(ed-sd) *24 * 60
  from a 
 where to_number(ed-sd) *24 * 60 < 40
像这样试试

with a as ( select sysdate sd, sysdate+(1/24/60)*39 ed from dual)
-- in with sysdate and sysdate + 39 minute
select to_char(sd,'dd.mm.yyyy hh24:mi:ss'),
       to_char(ed,'dd.mm.yyyy hh24:mi:ss'), 
       to_number(ed-sd) *24 * 60
  from a 
 where to_number(ed-sd) *24 * 60 < 40
使用

此外,请重写此条件

TRUNC(EXECUTION_START_DATE)=TRUNC(SYSDATE) 
这一个

EXECUTION_START_DATE >= TRUNC(SYSDATE) and EXECUTION_START_DATE < TRUNC(SYSDATE)+1
其中“神奇”数字1440是一天中的分钟数(24*60)


你能详细解释一下为什么它阻止oracle使用索引吗

请看一个简单的示例。首先,让我们创建一个充满随机数据的测试:

CREATE TABLE IW_MASTER_LOG AS
SELECT sysdate - 500*dbms_random.value as EXECUTION_START_DATE,
       t.* 
FROM all_objects t;

SELECT count(*) FROM IW_MASTER_LOG;
  COUNT(*)
----------
     74130
接下来在
EXECUTION\u START\u DATE
列上创建索引:

CREATE INDEX my_execution_index ON IW_MASTER_LOG( EXECUTION_START_DATE );
最后刷新表和索引统计信息:

exec DBMS_STATS.gather_table_stats( user, 'IW_MASTER_LOG' );
现在检查此查询的执行计划:

EXPLAIN PLAN FOR 
SELECT * FROM IW_MASTER_LOG
WHERE EXECUTION_START_DATE >= trunc( sysdate ) - 1 
  AND EXECUTION_START_DATE < trunc( sysdate );

SELECT * FROM table( DBMS_XPLAN.DISPLAY );
Plan hash value: 3519959109

-----------------------------------------------------------------------------------------------------------
| Id  | Operation                            | Name               | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                     |                    |   149 | 18476 |   152   (0)| 00:00:01 |
|*  1 |  FILTER                              |                    |       |       |            |          |
|   2 |   TABLE ACCESS BY INDEX ROWID BATCHED| IW_MASTER_LOG      |   149 | 18476 |   152   (0)| 00:00:01 |
|*  3 |    INDEX RANGE SCAN                  | MY_EXECUTION_INDEX |   149 |       |     2   (0)| 00:00:01 |
-----------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter(TRUNC(SYSDATE@!)>TRUNC(SYSDATE@!)-1)
   3 - access("EXECUTION_START_DATE">=TRUNC(SYSDATE@!)-1 AND 
              "EXECUTION_START_DATE"<TRUNC(SYSDATE@!))
正如您所看到的,查询执行完整的表扫描-函数
trunct
阻止Oracle使用该索引


正如所建议的那样:

您可以在函数上为此列创建索引,如创建索引 IW主日志上的id\u trunc\u esd(trunc(执行开始日期))

他完全正确,让我们看看他的建议:

CREATE INDEX another_index ON IW_MASTER_LOG( TRUNC(EXECUTION_START_DATE) );
exec DBMS_STATS.gather_table_stats( user, 'IW_MASTER_LOG' );
EXPLAIN PLAN FOR 
SELECT * FROM IW_MASTER_LOG
WHERE trunc(EXECUTION_START_DATE) = trunc( sysdate ) ;

SELECT * FROM table( DBMS_XPLAN.DISPLAY );
Plan hash value: 1627571743

-----------------------------------------------------------------------------------------------------
| Id  | Operation                           | Name          | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                    |               |   148 | 19536 |   142   (0)| 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID BATCHED| IW_MASTER_LOG |   148 | 19536 |   142   (0)| 00:00:01 |
|*  2 |   INDEX RANGE SCAN                  | ANOTHER_INDEX |   148 |       |     1   (0)| 00:00:01 |
-----------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - access(TRUNC(INTERNAL_FUNCTION("EXECUTION_START_DATE"))=TRUNC(SYSDATE@!))
完美-查询使用新索引。您可以按照АааааПааааааааааа 但是这个索引是有限的-它只能服务于带有
trunc(EXECUTION\u START\u DATE)=…
条件的查询。例如,它不能用于选择某个日期和此日期+10分钟之间的行-我们仍然需要在
EXECUTION\u START\u date
列上使用普通索引。如果我问我的DBA是否可以创建两个索引而不是一个,因为我太懒了,无法在查询中重写一个条件
trunc(date)
,那么他可能会在地毯上给我打电话。

使用

WITH IW_MASTER_LOG AS
  (SELECT SYSDATE AS EXECUTION_START_DATE,
    SYSDATE       AS EXECUTION_END_DATE
  FROM DUAL
  UNION ALL
  SELECT SYSDATE, SYSDATE+1/24/60*30 FROM DUAL
  UNION ALL
  SELECT SYSDATE, SYSDATE+1/24/60*41 FROM DUAL
  )
SELECT *
FROM IW_MASTER_LOG
WHERE (EXECUTION_END_DATE-EXECUTION_START_DATE)>=1/24/60*40
AND TRUNC(EXECUTION_START_DATE)                 = TRUNC(SYSDATE); --started today
此外,请重写此条件

TRUNC(EXECUTION_START_DATE)=TRUNC(SYSDATE) 
这一个

EXECUTION_START_DATE >= TRUNC(SYSDATE) and EXECUTION_START_DATE < TRUNC(SYSDATE)+1
其中“神奇”数字1440是一天中的分钟数(24*60)


你能详细解释一下为什么它阻止oracle使用索引吗

请看一个简单的示例。首先,让我们创建一个充满随机数据的测试:

CREATE TABLE IW_MASTER_LOG AS
SELECT sysdate - 500*dbms_random.value as EXECUTION_START_DATE,
       t.* 
FROM all_objects t;

SELECT count(*) FROM IW_MASTER_LOG;
  COUNT(*)
----------
     74130
接下来在
EXECUTION\u START\u DATE
列上创建索引:

CREATE INDEX my_execution_index ON IW_MASTER_LOG( EXECUTION_START_DATE );
最后刷新表和索引统计信息:

exec DBMS_STATS.gather_table_stats( user, 'IW_MASTER_LOG' );
现在检查此查询的执行计划:

EXPLAIN PLAN FOR 
SELECT * FROM IW_MASTER_LOG
WHERE EXECUTION_START_DATE >= trunc( sysdate ) - 1 
  AND EXECUTION_START_DATE < trunc( sysdate );

SELECT * FROM table( DBMS_XPLAN.DISPLAY );
Plan hash value: 3519959109

-----------------------------------------------------------------------------------------------------------
| Id  | Operation                            | Name               | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                     |                    |   149 | 18476 |   152   (0)| 00:00:01 |
|*  1 |  FILTER                              |                    |       |       |            |          |
|   2 |   TABLE ACCESS BY INDEX ROWID BATCHED| IW_MASTER_LOG      |   149 | 18476 |   152   (0)| 00:00:01 |
|*  3 |    INDEX RANGE SCAN                  | MY_EXECUTION_INDEX |   149 |       |     2   (0)| 00:00:01 |
-----------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter(TRUNC(SYSDATE@!)>TRUNC(SYSDATE@!)-1)
   3 - access("EXECUTION_START_DATE">=TRUNC(SYSDATE@!)-1 AND 
              "EXECUTION_START_DATE"<TRUNC(SYSDATE@!))
正如您所看到的,查询执行完整的表扫描-函数
trunct
阻止Oracle使用该索引


正如所建议的那样:

您可以在函数上为此列创建索引,如创建索引 IW主日志上的id\u trunc\u esd(trunc(执行开始日期))

他完全正确,让我们看看他的建议:

CREATE INDEX another_index ON IW_MASTER_LOG( TRUNC(EXECUTION_START_DATE) );
exec DBMS_STATS.gather_table_stats( user, 'IW_MASTER_LOG' );
EXPLAIN PLAN FOR 
SELECT * FROM IW_MASTER_LOG
WHERE trunc(EXECUTION_START_DATE) = trunc( sysdate ) ;

SELECT * FROM table( DBMS_XPLAN.DISPLAY );
Plan hash value: 1627571743

-----------------------------------------------------------------------------------------------------
| Id  | Operation                           | Name          | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                    |               |   148 | 19536 |   142   (0)| 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID BATCHED| IW_MASTER_LOG |   148 | 19536 |   142   (0)| 00:00:01 |
|*  2 |   INDEX RANGE SCAN                  | ANOTHER_INDEX |   148 |       |     1   (0)| 00:00:01 |
-----------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - access(TRUNC(INTERNAL_FUNCTION("EXECUTION_START_DATE"))=TRUNC(SYSDATE@!))
完美-查询使用新索引。您可以按照АааааПааааааааааа 但是这个索引是有限的-它只能服务于带有
trunc(EXECUTION\u START\u DATE)=…
条件的查询。例如,它不能用于选择某个日期和此日期+10分钟之间的行-我们仍然需要在
EXECUTION\u START\u date
列上使用普通索引。如果我问我的DBA是否可以创建两个索引而不是一个,因为我太懒了,无法在查询中重写一个条件
trunc(date)
,那么他可能会打电话给我

WITH IW_MASTER_LOG AS
  (SELECT SYSDATE AS EXECUTION_START_DATE,
    SYSDATE       AS EXECUTION_END_DATE
  FROM DUAL
  UNION ALL
  SELECT SYSDATE, SYSDATE+1/24/60*30 FROM DUAL
  UNION ALL
  SELECT SYSDATE, SYSDATE+1/24/60*41 FROM DUAL
  )
SELECT *
FROM IW_MASTER_LOG
WHERE (EXECUTION_END_DATE-EXECUTION_START_DATE)>=1/24/60*40
AND TRUNC(EXECUTION_START_DATE)                 = TRUNC(SYSDATE); --started today
Oracle日期表示为天数的分数,这意味着什么

1 - day
1/24 - hour
1/24/60 - minute
1/24/60*40 - 40 mins
TRUNC-忽略第二个参数返回日期时

在我的结果中使用WITH子句将在以下数据集中显示

07.15.2016 14:13:54 | 07.15.2016 14:13:54
07.15.2016 14:13:55 | 07.15.2016 14:43:55
07.15.2016 14:13:56 | 07.15.2016 14:54:56
查询只返回最后一条记录(需要什么,因为41分钟)

Oracle日期表示为天数的分数,这意味着什么

1 - day
1/24 - hour
1/24/60 - minute
1/24/60*40 - 40 mins
TRUNC-忽略第二个参数返回日期时

在我的结果中使用WITH子句将在以下数据集中显示

07.15.2016 14:13:54 | 07.15.2016 14:13:54
07.15.2016 14:13:55 | 07.15.2016 14:43:55
07.15.2016 14:13:56 | 07.15.2016 14:54:56

查询只返回最后一条记录(需要什么,因为需要41分钟)

Hi krokodilko,您能否详细说明为什么它阻止oracle使用索引。我也试过40分钟的间歇时间。它给出了一个错误“ORA-00932:不一致的数据类型:预期的数字得到了间隔天数到秒”krokodilko试图说,如果您在查询中使用TRUNC(执行开始日期),它不会在执行开始日期列上使用索引,因为它是一个函数,您可以在该列上创建索引,就像在IW主日志上创建索引id TRUNC esd一样(TRUNC(EXECUTION\u START\u DATE))感谢您的回复。:)嗨,krokodilko,您能详细解释一下为什么它阻止oracle使用索引吗。我也试过40分钟的间歇时间。它给出了一个错误“ORA-00932:不一致的数据类型:预期的数字得到了间隔天数到秒”krokodilko试图说,如果您在查询中使用TRUNC(执行开始日期),它不会在执行开始日期列上使用索引,因为它是一个函数,您可以在该列上创建索引,就像在IW主日志上创建索引id TRUNC esd一样谢谢你的回复。嗨,彼得,谢谢你提供的信息。但是,查询似乎无法获取预期的结果。我试着运行那个查询,它只返回了2条记录。但是我确信还有很多超过40分钟的记录。嗨,Arjun,我已经更新了我的查询-以前我忘了只过滤今天的记录。现在开始日期必须是今天。如果这个过程在第二天运行并结束,那没关系。你也会得到结果的。不幸的是,我一点也不知道,为什么你检索的行数少于你认为应该检索的行数,应该可以。谢谢你的回答:)嗨,彼得,谢谢你提供的信息。但是,查询似乎无法获取预期的结果。我试着运行那个查询,它只返回了2条记录。但是我确信还有很多超过40分钟的记录。嗨,Arjun,我已经更新了我的查询-以前我忘了只过滤今天的记录。现在开始日期必须是今天。如果这个过程在第二天运行并结束,那没关系。你会得到结果的