数据类型从 varchar2 到日期、数字等的隐式转换

Posted

技术标签:

【中文标题】数据类型从 varchar2 到日期、数字等的隐式转换【英文标题】:Implicit conversion of datatypes from varchar2 to date, number etc 【发布时间】:2021-02-02 16:29:44 【问题描述】:

假设我在表 Table_A 中有一些当前是 varchar2 值的列。

鉴于它们是正确的日期格式(通过带有 to_date 的更新语句格式化),并且我想将具有原始 varchar2 值的 Table_A 中的数据插入到具有相应日期列的 Table_B 中 - Oracle 会进行转换如果日期格式正确,则隐式从 varchar2 到 Date?

同样,我想知道 Oracle 是否会将存储为 Varchar2 的十进制数转换为目标表中具有相应正确格式的 Number(N,M)。

我问的原因是,看看我是否可以避免编写大型查询,这些查询必须在选择之前先切换列类型,然后再插入到目标表中。

【问题讨论】:

【参考方案1】:

你可以这样做,这都是关于NLS_DATE_FORMAT。 但有风险:

create table a(
  pk integer not null,
  dt varchar2(30)
);
create table b(
  pk integer not null,
  dt date
);
--
-- This example shows date truncation because of the nls_date_format
--
alter session set nls_date_format='DD-MON-YYYY';
insert into b values(1, sysdate);
select to_char(dt, 'YYYY-MM-DD HH24:MI:SS') dt from b;
-- 2021-02-02 11:53:05
insert into a select * from b;
select * from a;
-- 02-FEB-2021
delete b;
insert into b select * from a;
select to_char(dt, 'YYYY-MM-DD HH24:MI:SS') dt from b;
-- 2021-02-02 00:00:00

--
-- This example shows a working conversion
---
alter session set nls_date_format='YYYY-MM-DD HH24:MI:SS';
delete a;
delete b;
insert into b values(1, sysdate);
select to_char(dt, 'YYYY-MM-DD HH24:MI:SS') dt from b;
-- 2021-02-02 11:53:05
insert into a select * from b;
select * from a;
-- 2021-02-02 11:53:05
delete b;
insert into b select * from a;
select to_char(dt, 'YYYY-MM-DD HH24:MI:SS') dt from b;
-- 2021-02-02 11:53:05

--
-- This example shows a failure because of bad date mask.
--
alter session set nls_date_format='YYYY-MM-DD';
delete a;
delete b;
insert into b values(1, sysdate);
select to_char(dt, 'YYYY-MM-DD HH24:MI:SS') dt from b;
-- 2021-02-02 11:53:05
insert into a select * from b;
select * from a;
-- 2021-02-02
alter session set nls_date_format='Dy DD/MM HH24:MI:SS';
delete b;
insert into b select * from a;
-- ORA-01846: not a valid day of the week

简而言之,除非绝对必要,否则不要这样做。 如果必须这样做,请确保在 SQL 执行之前通过在脚本中设置 nls_date_mask 来控制它。

【讨论】:

【参考方案2】:

对于数字来说答案更容易 - 只要小数分隔符在所有表和列中保持一致。如果一个表中的列具有33.29 格式,而另一个表中的列具有33,29 格式,因为它使用逗号作为小数分隔符,您将遇到问题。

对于日期,它会有点复杂 - 特别是如果某些日期类似于 '12/31/2020' 而其他日期类似于 '12/31/2020 00:00:00'

如果所有数字的格式完全相同,并且所有日期的格式完全相同,它应该可以工作;对于日期,您需要确保 nls_date_format 与您的字符串格式相同(或使用 alter session 更改它),对于数字,您必须确保 nls_numeric_characters 显示相同的小数分隔符(并且,如果使用,相同的分组分隔符)作为你的数字字符串。

我可能会按照您对“玩”数据库(例如,用于测试)的建议进行操作 - 或者在您不能造成太大破坏的环境中。如果重要的事情依赖于数据库和其中的数据,我不会在生产中这样做。

【讨论】:

太棒了!正是我想听到的 :) 我已经更新了日期和数字的格式以对应于目标表格式以及 NLS - 只是想知道这是否足够,或者我是否必须花很长时间在选择和插入之前复制到新的间歇列的路径。我会按照您的建议进行尝试,并进行初步试验,看看它是否有效。非常感谢!

以上是关于数据类型从 varchar2 到日期、数字等的隐式转换的主要内容,如果未能解决你的问题,请参考以下文章

数据库界面修改时,出现不允许从数据类型 datetime 到 int 的隐式转换.请使用 CONVERT 函数来运行此查询。

不允许从数据类型 nvarchar 到 varbinary(max) 的隐式转换

不允许从数据类型 nvarchar 到 varbinary(max) 的隐式转换

从枚举类型 'enum UIViewAnimationOption 到不同枚举类型 uiviewanimation 的隐式转换

Spring JDBC for SQL Server - 使用 SQLXML 数据类型产生 SQLServerException:不允许从数据类型 xml 到 nvarchar(max) 的隐式转换

无法在 varbinary(max) 中插入空值并出现错误:不允许从数据类型 nvarchar 到 varbinary(max) 的隐式转换