Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 日期数据类型等于(=)vs.LIKE_Sql_Oracle - Fatal编程技术网

Sql 日期数据类型等于(=)vs.LIKE

Sql 日期数据类型等于(=)vs.LIKE,sql,oracle,Sql,Oracle,首先,我知道这个问题已经发布了。 在这里,我查询ORACLE数据库上的日期类型数据,当我以这种方式编写select语句时,我发现: SELECT ACCOUNT.ACCOUNT_ID, ACCOUNT.LAST_TRANSACTION_DATE FROM ACCOUNT WHERE ACCOUNT.LAST_TRANSACTION_DATE LIKE '30-JUL-07'; 我找到了我要找的所有行。但是当我使用等号=时: SELECT ACCOUNT.ACCOUNT_ID, ACCOUNT.

首先,我知道这个问题已经发布了。 在这里,我查询ORACLE数据库上的日期类型数据,当我以这种方式编写select语句时,我发现:

SELECT ACCOUNT.ACCOUNT_ID, ACCOUNT.LAST_TRANSACTION_DATE
FROM ACCOUNT
WHERE ACCOUNT.LAST_TRANSACTION_DATE LIKE '30-JUL-07';
我找到了我要找的所有行。但是当我使用等号
=
时:

SELECT ACCOUNT.ACCOUNT_ID, ACCOUNT.LAST_TRANSACTION_DATE
FROM ACCOUNT
WHERE ACCOUNT.LAST_TRANSACTION_DATE = '30-JUL-07';

我什么也得不到,即使除了等号没有什么不同。我能找到对此的解释吗?

日期字段不是字符串。在内部,当您使用
=
时,会对字符串进行隐式转换,这与任何内容都不匹配,因为您的字符串没有所需的精度

我猜想,
LIKE
语句与日期字段的行为有所不同,导致在比较中使用隐式通配符,从而消除了对任何精度的要求。本质上,您的
类似
是这样工作的:

SELECT ACCOUNT.ACCOUNT_ID, ACCOUNT.LAST_TRANSACTION_DATE
FROM ACCOUNT
WHERE ACCOUNT.LAST_TRANSACTION_DATE BETWEEN DATE('30-JUL-07 00:00:00.00000+00:00') AND DATE('30-JUL-07 23:59:59.99999+00:00');
SQL> select * from test_date where d = to_date('30-JUL-07', 'DD-MON-RR');

D
-----------

不应直接将日期与字符串进行比较。你所依赖的,这些规则很难记住

此外,您对日期格式的选择也不是最优的:年份有四位数字(Y2K bug?),并且并非所有语言都将一年中的第七个月命名为
JUL
。您应该使用类似于
YYYY/MM/DD
的内容

最后,Oracle中的日期是精确到秒的时间点所有日期都有一个时间组件,即使它是
00:00:00
。使用
=
运算符时,Oracle将比较日期和时间

下面是一个复制您描述的行为的测试用例:

SQL> create table test_date (d date);

Table created

SQL> alter session set nls_date_format = 'DD-MON-RR';

Session altered

SQL> insert into test_date values
  2     (to_date ('2007/07/30 11:50:00', 'yyyy/mm/dd hh24:mi:ss'));

1 row inserted

SQL> select * from test_date where d = '30-JUL-07';

D
-----------

SQL> select * from test_date where d like '30-JUL-07';

D
-----------
30/07/2007
使用
=
运算符时,Oracle会将常量字符串
2007年7月30日
转换为日期,并将该值与列进行比较,如下所示:

SELECT ACCOUNT.ACCOUNT_ID, ACCOUNT.LAST_TRANSACTION_DATE
FROM ACCOUNT
WHERE ACCOUNT.LAST_TRANSACTION_DATE BETWEEN DATE('30-JUL-07 00:00:00.00000+00:00') AND DATE('30-JUL-07 23:59:59.99999+00:00');
SQL> select * from test_date where d = to_date('30-JUL-07', 'DD-MON-RR');

D
-----------
使用
LIKE
运算符时,Oracle会将列转换为字符串,并将其与右侧进行比较,这相当于:

SQL> select * from test_date where to_char(d, 'DD-MON-RR') like '30-JUL-07';

D
-----------
30/07/2007
始终将日期与日期和字符串与字符串进行比较。相关问题:


假设
最后一次交易的日期
日期
列(或
时间戳
),那么这两种版本都是非常糟糕的做法

在这两种情况下,
DATE
列将根据当前NLS设置隐式转换为字符文本。这意味着不同的客户会得到不同的结果

使用日期文字时,请始终使用带有(!)格式掩码的
to_date()
,或使用ANSI日期文字。这样可以比较日期和日期,而不是字符串和字符串。因此,对于相等的比较,您应该使用:

LAST_TRANSACTION_DATE = to_date('30-JUL-07', 'dd-mon-yy')
请注意,使用“MON”仍然可能导致不同NLS设置的错误(
'DEC'
'DEZ'
'MAR'
'MRZ'
)。使用月数(和四位数年份)时,不太容易出错:

或者使用ANSI日期文字

LAST_TRANSACTION_DATE = DATE '2007-07-30'
现在,上面的查询很可能不返回任何内容的原因是,在Oracle
DATE
列中,时间也包含在内。上述日期文本隐式包含时间
00:00
。如果表中的时间不同(例如,
19:54
),则日期当然不相等

要解决此问题,您有不同的选择:

  • 使用表列上的
    trunc()
    将时间“标准化”到
    00:00
    trunc(上次交易日期)=日期'2007-07-30
    但是,这将阻止使用上次交易日期定义的索引

  • 之间使用
    
    
    最后一笔交易日期介于截止日期('2007-07-30 00:00:00’,'yyyy-mm dd hh24:mi:ss')和截止日期('2007-07-30 23:59:59’,'yyyy-mm dd hh24:mi:ss')
  • 第一个解决方案的性能问题可以通过在
    trunc(LAST\u TRANSACTION\u DATE)
    上创建一个索引来解决,该索引可由该表达式使用。但是表达式
    LAST\u TRANSACTION\u DATE='30-JUL-07'
    也阻止了索引的使用,因为在内部它被处理为
    to\u char(LAST\u TRANSACTION\u DATE)='30-JUL-07'

    要记住的重要事项:

  • 永远不要依赖隐式数据类型转换。它会在某个时候给你带来问题。始终比较正确的数据类型
  • Oracle
    DATE
    列始终包含作为比较规则一部分的时间

  • 我猜第一个只匹配
    2007年7月30日00:00:00
    ,而第二个匹配
    2007年7月30日**:*:**
    ?假设这些数据格式不在我的控制之下,我需要与2007年7月30日进行比较,我想我必须使用像这样的显式转换来转换到日期(“2007年7月30日”)。对吗?您必须使用带有两个参数(常量和格式:)的
    来确定日期。另外,与
    类似的
    严格来说是一个字符串运算符,因此不能很好地处理日期。上一次交易的日期=截止日期('30-07-2007','dd-mm-yyyy')有一个额外的“y”,请编辑。我不能自己编辑,因为我需要编辑至少6个字符:)谢谢我认为
    之间的
    也不能从索引中获益。