oracle 在SQL中错误使用trim()函数

bkkx9g8r  于 2023-04-05  发布在  Oracle
关注(0)|答案(2)|浏览(197)

SQL命令未给出预期结果。

UPDATE table SET DATE_COL=trim(DATE_COL).

未生成错误消息。
我错误地使用TRIM()删除Oracle表中日期类型列上的空间。结果如下:如果日期在(30.12.1899-31.12.1949)之间,则将100年添加到结果中。如果范围是(1.1.1950 - 31.12.2049),则将100年减去。如果范围是1.1.1950-31.12.2049,则结果不会改变。当然,它根本不应该用于日期类型。
警告在错误的对象上使用trim()

hrysbysz

hrysbysz1#

如果您这样做:

UPDATE table_name
SET DATE_COL=trim(DATE_COL)

那么你实际上是在做:

UPDATE table_name
SET DATE_COL = TO_DATE(TRIM(TO_CHAR(DATE_COL)))

这与以下内容相同:

UPDATE table_name
SET DATE_COL = TO_DATE(
                 trim(
                   TO_CHAR(
                     DATE_COL,
                     ( SELECT value
                       FROM   NLS_SESSION_PARAMETERS
                       WHERE  parameter = 'NLS_DATE_FORMAT' )
                   )
                 ),
                 ( SELECT value
                   FROM   NLS_SESSION_PARAMETERS
                   WHERE  parameter = 'NLS_DATE_FORMAT' )
               );

如果你的NLS_DATE_FORMATYYYY-MM-DD HH24:MI:SS,那么你的约会不会发生任何事情。
但是如果NLS_DATE_FORMATDD-MON-RR,那么日期1920-01-01T12:34:56将被转换为01-JAN-20,然后转换回日期2020-01-01T00:00:00,这将改变世纪(因为RR模型将20解释为当前世纪2020)并将时间分量截断为午夜。
最简单的解决方案是使用ROLLBACK将数据库恢复到最近的提交。如果您已经提交了,则需要从最近的备份中恢复表。

ws51t4hk

ws51t4hk2#

这种行为可能不是你想要或期望的,但它是文档中所说的会发生的。The trim function说:
trim_character和trim_source都可以是VARCHAR 2或任何可以隐式转换为VARCHAR 2的数据类型。
和日期可以隐式地转换为字符串,反之亦然。
当你执行trim(DATE_COL)时,日期值被隐式转换为字符串,就像你执行trim(to_char(DATE_COL))一样,这将使用你的NLS设置,特别是NLS_DATE_FORMAT。从你所看到的来看,你似乎将其设置为'DD-MON-RR'。因此,例如1899-12-31被格式化为字符串'31-DEC-99'。然后该字符串值被修剪,请注意,如果原始日期具有非午夜时间,则该时间现在也已丢失。
然后,当你用DATE_COL=trim(DATE_COL)将该值赋回日期列时,它会隐式地转换回来,实际上是DATE_COL=to_date(trim(to_char(DATE_COL)))to_date()再次使用了你的NLS设置,所以对于那个示例日期,你现在是在做DATE_COL=to_date('31-DEC-99')。因为它也使用了NLS_DATE_FORMAT,所以它实际上是to_date('31-DEC-99', 'DD-MON-RR'),RR格式元素行为表明它将被解释为1999。
您可以看到日期范围in this fiddle发生了什么,中间字符串值以及如何将其转换回日期。
| 旧完整日期|旧STR|新日期|新完整日期|
| --------------|--------------|--------------|--------------|
| 1849-12-31 23:59:59|一九四九年十二月三十一日|一九四九年十二月三十一日|2049-12-31 00:00:00|
| 1850年1月1日00时00分|2050年1月1日|2050年1月1日|1950-01-01 00:00:00|
| 2019 - 09 -12 00:00:00|一九九九年十二月三十一日|一九九九年十二月三十一日|一九九九年十二月三十一日上午十时|
| 1900年1月1日00时00分|2000年1月1日|2000年1月1日|二○ ○ ○年一月一日上午十时|
| 1949-12-31 00:00:00|一九四九年十二月三十一日|一九四九年十二月三十一日|2049-12-31 00:00:00|
| 1950-01-01 00:00:00|2050年1月1日|2050年1月1日|1950-01-01 00:00:00|
| 一九九九年十二月三十一日上午十时|一九九九年十二月三十一日|一九九九年十二月三十一日|一九九九年十二月三十一日上午十时|
| 二○ ○ ○年一月一日上午十时|2000年1月1日|2000年1月1日|二○ ○ ○年一月一日上午十时|
| 2049-12-31 00:00:00|一九四九年十二月三十一日|一九四九年十二月三十一日|2049-12-31 00:00:00|
| 2019 -01- 12 00:00:00|2050年1月1日|2050年1月1日|1950-01-01 00:00:00|
| 二○九九年十二月三十一日零时|一九九九年十二月三十一日|一九九九年十二月三十一日|一九九九年十二月三十一日上午十时|
这个小提琴还显示,如果NLS_DATE_FORMAT中有一个4位数的年份,你会保留世纪(但仍然截断时间)。这并不是说你应该依赖隐式转换或NLS设置,它只是演示效果。
很不幸,它在做你让它做的事。
数据库无法猜测你要做什么--它只知道你告诉它做什么--或者你什么时候做了,而不是打算依赖隐式转换。编码人员有责任使用适当的函数来实现他们想要实现的目标。

相关问题