PL/SQL - ORACLE: ORA-01843: 不是有效月份

PL/SQL - ORACLE: ORA-01843: not a valid month

我想在 oracle 数据库版本 11.2.0.4

上的 PL/SQL ETL 过程中的 table 中插入数据并带有时间戳列

如果我在 Toad 中 运行 "Create INSERT from seletcted row" 我得到以下 SQL 命令:

 Insert into xxxx
   (ID, ITEM, ITEMSIZE, QUALITY, MATERIAL, 
    COLOUR, IMAGEURL, CREATIONDATE, SAMPLEITEMNUMBER, ITEMNUMBER)
 Values
   (111, 339079775, '1', 'Microfaser PRIMABELLE®', 'TEXTILE', 
    '1 (=creme)', 'url', TO_TIMESTAMP('27.06.2016 15:49:35.000000','DD.MM.YYYY HH24:MI:SS.FF'), 'xxx', 'xxxx');
COMMIT;

在 PL/SQL 中,我生成了一个 VARCHAR2/String,它看起来是一样的:

v_sql :=
                                'INSERT INTO xxxx'
                             || p_importpostfix
                             || '  VALUES ('
                             || seq_xxxx.NEXTVAL
                             || ','
                             || v_rec.item_id
                             || ', '''
                             || v_size
                             || ''','''
                             || v_quality
                             || ''','''
                             || v_material
                             || ''','''
                             || v_colour
                             || ''','''
                             || NULL
                             || ''',to_timestamp('''|| to_char( sysdate, 'DD.MM.YYYY HH24:MI:SS')||''',''DD.MM.YYYY HH24:MI:SS.FF''),'''
                             || v_rec.vid
                             || ''','''
                             || v_rec.vid
                             || ''')';

如果我 运行 在整个过程之外单独执行该过程,它可以正常工作。 没有错误发生。

如果我 运行 由数据库 JOB 启动的完整进程,我将得到一个 ORACLE:

ORA-01843: not a valid month error.

我已经阅读了有关此问题的其他主题,但不了解我的问题所在。

不确定这是否是问题所在,但按字面意义使用 SYSDATE 似乎更容易。

而且您似乎插入了字符串 'NULL'。如果要插入 NULL 值,则不需要使用多个单引号,因为最终字符串不需要单引号来插入 NULL 值。

v_sql :=
                                'INSERT INTO xxxx'
                             || p_importpostfix
                             || '  VALUES ('
                             || seq_xxxx.NEXTVAL
                             || ','
                             || v_rec.item_id
                             || ', '''
                             || v_size
                             || ''','''
                             || v_quality
                             || ''','''
                             || v_material
                             || ''','''
                             || v_colour
                             || ''','
                             || 'NULL,'
                             || 'SYSDATE,'
                             || ''''
                             || v_rec.vid
                             || ''','''
                             || v_rec.vid
                             || ''')';

编辑

与其尝试构建这样的查询,不如使用参数化查询。

    v_sql := 'INSERT INTO xxxx' || p_importpostfix || ' VALUES(:1,:2,:3,:4,:5,:7,:8,:9,:10)';
    v_null := NULL;
    EXECUTE IMMEDIATE v_sql USING IN seq_xxxx.NEXTVAL, 
                                  IN v_rec.item_id, 
                                  IN v_size,
                                  IN v_quality,
                                  IN v_material,
                                  IN v_colour,
                                  IN v_null,
                                  IN SYSTIMESTAMP,
                                  IN v_rec.vid,
                                  IN v_rec.vid;

想象一下,如果您的某个值包含 '...

更多信息on EXECUTE IMMEDIATE on Oracle documentation。不过我认为您需要一个 Oracle 帐户。

你能显示目标的 DESC table 吗? 确保数据类型没有不匹配?

每当您构建这些动态字符串时,我总是发现使用 "q" 引号格式更容易帮助减少 所有这些 repeated/escaped 引号...使它更容易阅读:

从 TOAD 的查询开始:

  Insert into xxxx                                                                                           
  (ID, ITEM, ITEMSIZE, QUALITY, MATERIAL,                                                                      
     COLOUR, IMAGEURL, CREATIONDATE, SAMPLEITEMNUMBER, ITEMNUMBER)                                             
  Values                                                                                                       
  (111, 339079775, '1', 'Microfaser PRIMABELLE®', 'TEXTILE',                                                   
     '1 (=creme)', 'url', TO_TIMESTAMP('27.06.2016 15:49:35.000000','DD.MM.YYYY HH24:MI:SS.FF'), 'xxx', 'xxxx');

去掉分号,每行用 q'[ ]' 包裹起来:

  v_sql :=
  q'[ Insert into xxxx                                                                                            ]'||CHR(10)||
  q'[ (ID, ITEM, ITEMSIZE, QUALITY, MATERIAL,                                                                       ]'||CHR(10)||
  q'[    COLOUR, IMAGEURL, CREATIONDATE, SAMPLEITEMNUMBER, ITEMNUMBER)                                              ]'||CHR(10)||
  q'[ Values                                                                                                        ]'||CHR(10)||
  q'[ (111, 339079775, '1', 'Microfaser PRIMABELLE®', 'TEXTILE',                                                    ]'||CHR(10)||
  q'[    '1 (=creme)', 'url', TO_TIMESTAMP('27.06.2016 15:49:35.000000','DD.MM.YYYY HH24:MI:SS.FF'), 'xxx', 'xxxx') ]'||CHR(10)||

添加 CHR(10) 只是为了使字符串更具可读性 - 这是为了我们的利益。不是甲骨文的。 接下来,添加一个 RTRIM,因为所有这些额外的空格都可以使字符串变大、变快 :) (对于较大的字符串,我使用了使用相同技术的 CLOB)

  v_sql :=
  RTRIM(q'[ Insert into xxxx                                                                                            ]')||CHR(10)||
  RTRIM(q'[ (ID, ITEM, ITEMSIZE, QUALITY, MATERIAL,                                                                       ]')||CHR(10)||
  RTRIM(q'[    COLOUR, IMAGEURL, CREATIONDATE, SAMPLEITEMNUMBER, ITEMNUMBER)                                              ]')||CHR(10)||
  RTRIM(q'[ Values                                                                                                        ]')||CHR(10)||
  RTRIM(q'[ (111, 339079775, '1', 'Microfaser PRIMABELLE®', 'TEXTILE',                                                    ]')||CHR(10)||
  RTRIM(q'[    '1 (=creme)', 'url', TO_TIMESTAMP('27.06.2016 15:49:35.000000','DD.MM.YYYY HH24:MI:SS.FF'), 'xxx', 'xxxx') ]')||CHR(10)||

接下来,我们需要为每个要替换的值输入 "placeholders":

  v_sql :=
  RTRIM(q'[ Insert into xxxx<tab_name>                                                                                    ]')||CHR(10)||
  RTRIM(q'[ (ID, ITEM, ITEMSIZE, QUALITY, MATERIAL,                                                                       ]')||CHR(10)||
  RTRIM(q'[    COLOUR, IMAGEURL, CREATIONDATE, SAMPLEITEMNUMBER, ITEMNUMBER)                                              ]')||CHR(10)||
  RTRIM(q'[ Values                                                                                                        ]')||CHR(10)||
  RTRIM(q'[ (seq_xxxx.nextval, 339079775, '1', 'Microfaser PRIMABELLE®', 'TEXTILE',                                       ]')||CHR(10)||
  RTRIM(q'[    '1 (=creme)', 'url', TO_TIMESTAMP('27.06.2016 15:49:35.000000','DD.MM.YYYY HH24:MI:SS.FF'), 'xxx', 'xxxx') ]')||CHR(10)||

其余的,使用绑定变量:

  v_sql :=
  RTRIM(q'[ Insert into xxxx<tab_name>                                         ]')||CHR(10)||
  RTRIM(q'[ (ID, ITEM, ITEMSIZE, QUALITY, MATERIAL,                            ]')||CHR(10)||
  RTRIM(q'[    COLOUR, IMAGEURL, CREATIONDATE, SAMPLEITEMNUMBER, ITEMNUMBER)   ]')||CHR(10)||
  RTRIM(q'[ Values                                                             ]')||CHR(10)||
  RTRIM(q'[ (seq_xxxx.nextval, :1, :2, :3, :4,                                 ]')||CHR(10)||
  RTRIM(q'[    :5, NULL, SYSTIMESTAMP, :6, :7 )                                ]')||CHR(10)||

接下来,在运行时,您替换您的 table 名称 "piece"(您在这里需要动态 sql 的唯一原因...)

  v_runsql := REPLACE ( v_sql, '<tab_name>', p_importpostfix );

现在您可以做几件事...通过显示来验证 SQL:

  dbms_output.put_line ( v_runsql );

然后执行它,使用绑定变量"properly":

  execute immediate v_runsql USING v_rec.item_id, v_size, v_quality, v_material, v_colour, v_rec.vid, v_rec.vid;