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;
我想在 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;