在 Oracle 中从一个 table 插入到另一个时,将多个 VARCHAR 字段组合为 1 DATE?

Combining multiple VARCHAR fields as 1 DATE when inserting from one table to another in Oracle?

我正在尝试创建一个简短的脚本,它将获取 Table1 中的所有字段并将它们插入到 Table2 中。基本字段(col1、col2、col3 等)我已经被这样的东西覆盖了:

INSERT INTO Table1 (col1, col2, col3, col4, col5, col6, col7)
             SELECT col1, col2, col3, col4, col5, SYSDATE, USER
FROM Table2

对于表 1 中的 col8col9,我有点卡住了。例如 col8/col9DATE 数据类型,需要通过分别将表 1 中的 col6/col7/col8col9/col10/col11 组合在一起来插入。其中每一个定义如下:

col6/col9  -- VARCHAR2 (2Byte) // Month
col7/col10 -- VARCHAR2 (2Byte) // Day
col8/col11 -- VARCHAR2 (4Byte) // Year

在线查找 我尝试了以下方法,但收到 "not a valid month":

INSERT INTO Table1 (......)
SELECT ...., TO_DATE(TOCHAR(col6, '00') || TO_CHAR(col7, '00') || TO_CHAR(col8, '9999'), 'MM/DD/YYYY'), .....
FROM Table 2

有谁知道如何得到我想要的东西并将 3 个特定的 VARCHAR 字段组合为 DATE 以作为 Table1 中的 1 个字段插入?

我不能肯定地说这就是你 运行 正在进入的,但是当我 运行

SELECT TO_CHAR(1,'00') FROM dual;

输出在预期的 01 前面多了一个 space。我会将对 TO_CHAR() 的调用包装在对 TRIM() 的调用中,以删除任何此类 spaces.

SELECT TRIM(TO_CHAR(1,'00') FROM dual;

我还注意到您的连接与您提供的格式掩码不匹配。您的格式掩码有分隔 /,但您没有将它们连接到您的字符串中。您的输出最好是 MMDDYYYY。考虑将其添加到您的连接中,或者更改您的掩码。

INSERT INTO Table1 (......) SELECT ...., TO_DATE(TO_CHAR(col6, 'FM00') || TO_CHAR(col7, 'FM00') || TO_CHAR(col8, 'FM9999'), 'MMDDYYYY'), ..... FROM Table 2

恕我直言,这有帮助。您的日期格式字符串错误,to_char 格式也错误。应该工作...

如果您的列中的无效值始终为零,如您在评论中所说,那么您可以使用固定值 - 一个虚拟日期,或者更合理地让新列为 null - 带有 case 语句:

SELECT ...., CASE
    WHEN TRIM('0' FROM col6) IS NULL OR TRIM('0' FROM col7) IS NULL
      OR TRIM('0' FROM col8) IS NULL THEN NULL
    ELSE TO_DATE(LPAD(col6, 2, '0') || LPAD(col7, 2, '0') || LPAD(col8, 4, '0'),
      'MMDDYYYY')
  END, ...

TRIM 从值中删除零,然后检查是否还有任何剩余,这会一次性捕获 0 和 00(以及 col8 的 000 和 0000)。

LPAD 在值左侧填充零,例如,值 7 将变为 07 - 这很重要,因为您需要连接的值来匹配日期格式模型,如果没有前导零,您将结束得到非常混乱和无效的结果。

请注意,我根本没有使用 TO_CHAR。由于您的源列已经是字符串,您实际上是在隐式转换为数字,然后显式转换回字符串。使用 FM 修饰符或 TRIM 将具有与 LPAD 相同的效果,但会做更多的工作。

作为 CTE 中一些示例值的快速演示:

with t as (
  select '0' as col6, '0' as col7, '0' as col8 from dual
  union all select '00', '00', '0000' from dual
  union all select '08', '31', '2008' from dual
  union all select '7', '4', '2012' from dual
)
select col6, col7, col8,
  CASE
    WHEN TRIM('0' FROM col6) IS NULL OR TRIM('0' FROM col7) IS NULL
      OR TRIM('0' FROM col8) IS NULL THEN NULL
    ELSE TO_DATE(LPAD(col6, 2, '0') || LPAD(col7, 2, '0') || LPAD(col8, 4, '0'),
      'MMDDYYYY')
  END as my_date
from t;

COL6 COL7 COL8 MY_DATE  
---- ---- ---- ----------
0    0    0              
00   00   0000           
08   31   2008 2008-08-31
7    4    2012 2012-07-04

如果您有其他无效值,这仍然会影响它们 - 例如 09/31/2000,其中该月的天数是错误的。目前尚不清楚您的数据是否属于这种情况。如果是,那么您可以编写一个函数来尝试转换传递的任何内容,如果由于任何原因无效,则静默 return null。