where子句问题

时间:2017-11-13 21:42:28

标签: sql oracle

每当我重新排列where子句的条件时,我都会看到不同的查询结果;我想弄清楚为什么会这样。我被要求尝试弄清楚发生了什么,所以我可以使用一些帮助来确定可能导致问题的原因。要清楚,我们在运行select语句时没有收到错误,但是收到了意外的数据结果。这是一个Oracle数据库(我相信10克)。我们对同一领域有两个条件。第一个是确保结果大于30年前(这个数据库不是我自己设置的,但是拥有该应用程序的团队决定将created_date改为30,这是一个好主意)....第二个是更具体的日期范围是9月1日到10月1日。

SELECT created_date
FROM tableName
WHERE 
created_date > sysdate - 11000 -- 30 years in the past
AND short_name like 'FOO%'
AND trunc(created_date) BETWEEN TO_DATE('09-01-2017', 'MM-DD-YYYY')  
AND TO_DATE('10-01-2017', 'MM-DD-YYYY')

当运行上面的查询时,我们会在where子句末尾的条件之外接收带有created_date的结果。

但是,当我将created_date和sysdate之间的比较放在两个日期之间的比较后,我们会收到正确的结果。

SELECT created_date
FROM tableName
WHERE 
short_name like 'FOO%'
AND trunc(created_date) BETWEEN TO_DATE('09-01-2017', 'MM-DD-YYYY')  
AND TO_DATE('10-01-2017', 'MM-DD-YYYY')
AND created_date > sysdate - 11000 -- 30 years in the past

另外,我删除了“AND trunc(created_date)BETWEEN TO_DATE('09 -01-2017','MM-DD-YYYY')”的截断部分“到”AND created_date BETWEEN TO_DATE('09 -01-2017 ','MM-DD-YYYY')“并在之前或之后通过sysdate比较收到预期结果。

SELECT created_date
    FROM tableName
    WHERE 
    created_date > sysdate - 11000 -- 30 years in the past
    AND short_name like 'FOO%'
    AND created_date BETWEEN TO_DATE('09-01-2017', 'MM-DD-YYYY')  
    AND TO_DATE('10-01-2017', 'MM-DD-YYYY')

编辑:

  1. 数据库中有很多记录。创建日期为22-Sep-17只有1个结果。

    SELECT created_date
    FROM tableName
    WHERE 
    created_date > sysdate - 11000 -- 30 years in the past
    AND short_name like 'FOO%'
    AND trunc(created_date) BETWEEN TO_DATE('09-01-2017', 'MM-DD-YYYY')  
    AND TO_DATE('10-01-2017', 'MM-DD-YYYY')
    
  2. 生成25个条目,created_date为17-Feb-04,1个为22-Sep-17。

    1. 我理解sysdate - 11,000多了30多年。目前的要求是检查11000天而不是30年。我估计今年的假期。使用sysdate是因为被认为是旧的或更新的记录将使用created_date放置,而不是sysdate - 11000.我理解这在此查询中已经存在另一个日期范围条件时没有任何意义,但该解决方案已经构建并且被罚下来。为了做出改变,我需要弄清楚为什么我得到了我得到的东西,这就是我在这里发帖的原因。
    2. 第二个日期范围,在本例中为09-01-2017和10-01-2017,是传入的参数,因此它们可以是从过去的任何一天到今天的任何范围。我知道这是一个糟糕的设计,但我没有建立它。
    3.   

      这些将为两者之间的值提供两个微妙的不同结果   2017-10-01 00:00:01和2017-10-01 23:59:59查询使用TRUNC   将包括那个没有TRUNC范围的范围   排除。

      预期的结果是在22-Sep-17的日期范围内返回记录;但是,我们收到了25条记录,所有记录都是日期为17-Feb-04 ....如果我删除created_date> sysdate - 11000我也收到了唯一一条记录。

1 个答案:

答案 0 :(得分:1)

  

首先要确保结果大于30年前

你不减去30年,你减去11,000天大约(取决于闰年)30年零42天。

如果您想减去30年,请使用:

ADD_MONTHS( date_value, -30 * 12 )
  

第二个是更具体的日期范围是9月1日到10月1日。

这使得第一个条件无关紧要 - 如果它在2017-09-012017-10-01之间,则它将在过去30年内,并且您不需要第一个条件。

  

我删除了" AND trunc(created_date) BETWEEN TO_DATE('09-01-2017', 'MM-DD-YYYY')"的截断部分到" AND created_date BETWEEN TO_DATE('09-01-2017', 'MM-DD-YYYY')"并在之前或之后通过sysdate比较收到预期结果。

这些将为2017-10-01 00:00:012017-10-01 23:59:59之间的值提供两个微妙不同的结果。使用TRUNC的查询将包含不包含TRUNC范围的范围。

此外,使用TRUNC意味着Oracle不会在created_date列上建立索引(并且需要TRUNC( created_date )上基于函数的索引)。如果你想使用一个索引,那么只需使用该列并测试它是否大于或等于范围的开始并且小于范围的结束加上一天(包括最多23:59:59的那天)。

TRUNC查询的简化等效项为:

SELECT created_date
FROM   tableName
WHERE  short_name like 'FOO%'
AND    created_date >= DATE '2017-09-01'                    -- range start
AND    created_date <  DATE '2017-10-01' + INTERVAL '1' DAY -- range end + 1 day
相关问题