Sql 日期数据类型等于(=)vs.LIKE
首先,我知道这个问题已经发布了。 在这里,我查询ORACLE数据库上的日期类型数据,当我以这种方式编写select语句时,我发现: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.
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'
现在,上面的查询很可能不返回任何内容的原因是,在OracleDATE
列中,时间也包含在内。上述日期文本隐式包含时间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'
要记住的重要事项:
DATE
列始终包含作为比较规则一部分的时间我猜第一个只匹配
2007年7月30日00:00:00
,而第二个匹配2007年7月30日**:*:**
?假设这些数据格式不在我的控制之下,我需要与2007年7月30日进行比较,我想我必须使用像这样的显式转换来转换到日期(“2007年7月30日”)。对吗?您必须使用带有两个参数(常量和格式:)的来确定日期。另外,与
类似的严格来说是一个字符串运算符,因此不能很好地处理日期。上一次交易的日期=截止日期('30-07-2007','dd-mm-yyyy')有一个额外的“y”,请编辑。我不能自己编辑,因为我需要编辑至少6个字符:)谢谢我认为之间的也不能从索引中获益。