ORA-38101: INSERT VALUES 子句中的列无效:
Posted
技术标签:
【中文标题】ORA-38101: INSERT VALUES 子句中的列无效:【英文标题】:ORA-38101: Invalid column in the INSERT VALUES Clause: 【发布时间】:2012-05-17 19:46:20 【问题描述】:因此,我正在通过创建一个工具来对数据进行去规范化以进行比较,从而测试我的规范化数据的准确性。在这样做的同时,我正在研究这个工具的新技术,而不是我通常会做的事情(使用游标并循环插入/更新)所以我遇到了两个我想尝试的项目,它们是批量集合和合并语句.我的问题是我在寻找利用批量收集的最佳方式时遇到了一些麻烦。
编辑:
好的,所以我在批量收集时找到了我的问题/解决方案。这实际上是我获取它的方式。我没有使用 forall 语句,而是将其更改为 for 并在其下方添加了一个循环。这导致发现更多错误。我试图调用存储在 indx 中的值的方式是错误的,所以我已经纠正了。现在我似乎遇到的唯一问题是标题中提到的错误。由于某种原因,在我的合并中,我尝试在插入中使用的第一个值会引发以下错误:
PL/SQL:ORA-38101:INSERT VALUES 子句中的列无效:“TMI”.“MACHINE_INTERVAL_ID” ORA-06550:第 92 行,第 7 列:
所以我现在想知道的是为什么我会收到这个错误。我理解我的插入值无效的概念。但我不完全明白为什么会这样。
这是有问题的合并语句:
MERGE INTO TEST_MACHINE_INTERVAL TMI
USING (SELECT * FROM TEST_MACHINE_INTERVAL) OTMI
ON (TMI.MACHINE_INTERVAL_ID = OTMI.MACHINE_INTERVAL_ID)
WHEN MATCHED THEN
UPDATE SET TMI.MACHINE_INTERVAL_ID = OTMI.MACHINE_INTERVAL_ID, TMI.START_DATE_TIME = OTMI.START_DATE_TIME,
TMI.INTERVAL_DURATION = OTMI.INTERVAL_DURATION, TMI.CALC_END_TIME = OTMI.CALC_END_TIME,
TMI.MACHINE_NAME = OTMI.MACHINE_NAME, TMI.SITE_NAME = OTMI.SITE_NAME,
TMI.OPERATOR_INSTANCE = OTMI.OPERATOR_INSTANCE, TMI.OPERATOR_INSTANCE2 = OTMI.OPERATOR_INSTANCE2,
TMI.OPERATOR_INSTANCE3 = OTMI.OPERATOR_INSTANCE3, TMI.SHIFT_NAME = OTMI.SHIFT_NAME,
TMI.INTERVAL_CATEGORY = OTMI.INTERVAL_CATEGORY, TMI.NTP_CATEGORY_NAME = OTMI.NTP_CATEGORY_NAME,
TMI.MACHINE_MODE = OTMI.MACHINE_MODE, TMI.JOB_LOAD_STATE_NAME = OTMI.JOB_LOAD_STATE_NAME,
TMI.RAW_SOURCE_MSG_TYPE = OTMI.RAW_SOURCE_MSG_TYPE
WHEN NOT MATCHED THEN
INSERT (TMI.MACHINE_INTERVAL_ID, TMI.START_DATE_TIME, TMI.INTERVAL_DURATION, TMI.CALC_END_TIME,
TMI.MACHINE_NAME, TMI.SITE_NAME, TMI.OPERATOR_INSTANCE, TMI.OPERATOR_INSTANCE2,
TMI.OPERATOR_INSTANCE3, TMI.SHIFT_NAME, TMI.INTERVAL_CATEGORY, TMI.NTP_CATEGORY_NAME,
TMI.MACHINE_MODE, TMI.JOB_LOAD_STATE_NAME, TMI.RAW_SOURCE_MSG_TYPE )
VALUES (MACHINE_INTERVAL_ID, START_DATE_TIME, INTERVAL_DURATION, CALC_END_TIME,
MACHINE_NAME, SITE_NAME, OPERATOR_INSTANCE, OPERATOR_INSTANCE2, OPERATOR_INSTANCE3,
SHIFT_NAME, INTERVAL_CATEGORY, NTP_CATEGORY_NAME, MACHINE_MODE,
JOB_LOAD_STATE_NAME, RAW_SOURCE_MSG_TYPE);
下面是我新修改的代码的完整版:
-- Denormaliztion of machine_interval Table.
-- Is used to take all intervals from interval_table and convert it from
-- foreign keys to corresponding names.
DECLARE
START_DATE_TIME TIMESTAMP(6) WITH TIME ZONE;
CALC_END_TIME TIMESTAMP(6) WITH TIME ZONE;
MACHINE_NAME VARCHAR2(256);
SITE_NAME VARCHAR2(256);
OPERATOR_INSTANCE VARCHAR2(256);
OPERATOR_INSTANCE2 VARCHAR2(256);
OPERATOR_INSTANCE3 VARCHAR2(256);
SHIFT_NAME VARCHAR2(256);
INTERVAL_CATEGORY VARCHAR2(256);
NPT_CATEGORY_NAME VARCHAR2(256);
MACHINE_MODE VARCHAR2(256);
JOB_LOAD_STATE_NAME VARCHAR2(256);
RAW_SOURCE_MSG_TYPE VARCHAR2(256);
INTERVAL_DURATION NUMBER;
MACHINE_INTERVAL_ID NUMBER;
--step one: Get all the intervals and store them into a cursor
CURSOR INTERVAL_CUR IS
SELECT *
FROM MACHINE_INTERVAL
ORDER BY START_DATE_TIME ASC;
TYPE TOTAL_MACHINE_INTERVALS IS
TABLE OF interval_cur%rowtype
INDEX BY PLS_INTEGER;
MACHINE_INTERVAL_ROW TOTAL_MACHINE_INTERVALS;
BEGIN
--step two: Make sure Test_Machine_interval is empty.
DELETE FROM TEST_MACHINE_INTERVAL;
OPEN INTERVAL_CUR;
LOOP
FETCH INTERVAL_CUR BULK COLLECT INTO MACHINE_INTERVAL_ROW LIMIT 100;
--step three: Loop through all the intervals.
FOR INDX IN 1..MACHINE_INTERVAL_ROW.COUNT
LOOP
--step four: Gather all datavalues needed to populate test_machine_interval.
MACHINE_INTERVAL_ID := MACHINE_INTERVAL_ROW(indx).MACHINE_INTERVAL_ID;
START_DATE_TIME := MACHINE_INTERVAL_ROW(indx).START_DATE_TIME;
CALC_END_TIME := MACHINE_INTERVAL_ROW(indx).CALC_END_TIME;
INTERVAL_DURATION := MACHINE_INTERVAL_ROW(indx).INTERVAL_DURATION;
INTERVAL_CATEGORY := MACHINE_INTERVAL_ROW(indx).INTERVAL_CATEGORY;
RAW_SOURCE_MSG_TYPE := MACHINE_INTERVAL_ROW(indx).RAW_SOURCE_MSG_TYPE;
SELECT M.MACHINE_NAME INTO MACHINE_NAME
FROM MACHINE M
WHERE MACHINE_ID = MACHINE_INTERVAL_ROW(indx).MACHINE_ID;
SELECT S.SITE_NAME INTO SITE_NAME
FROM SITE S
LEFT OUTER JOIN MACHINE M ON M.SITE_ID = S.SITE_ID
WHERE M.MACHINE_ID = MACHINE_INTERVAL_ROW(indx).MACHINE_ID;
SELECT O.OPERATOR_NAME INTO OPERATOR_INSTANCE
FROM OPERATOR_INSTANCE OI
LEFT OUTER JOIN OPERATOR O ON OI.OPERATOR_ID = O.OPERATOR_ID
WHERE OI.OPERATOR_INSTANCE_ID = MACHINE_INTERVAL_ROW(indx).OPERATOR_INSTANCE_ID;
SELECT O.OPERATOR_NAME INTO OPERATOR_INSTANCE2
FROM OPERATOR_INSTANCE OI
LEFT OUTER JOIN OPERATOR O ON OI.OPERATOR_ID = O.OPERATOR_ID
WHERE OI.OPERATOR_INSTANCE_ID = MACHINE_INTERVAL_ROW(indx).OPERATOR_INSTANCE_ID_2;
SELECT O.OPERATOR_NAME INTO OPERATOR_INSTANCE3
FROM OPERATOR_INSTANCE OI
LEFT OUTER JOIN OPERATOR O ON OI.OPERATOR_ID = O.OPERATOR_ID
WHERE OI.OPERATOR_INSTANCE_ID = MACHINE_INTERVAL_ROW(indx).OPERATOR_INSTANCE_ID_3;
SELECT NPT_CATEGORY_NAME INTO NPT_CATEGORY_NAME
FROM NPT_CATEGORY
WHERE NPT_CATEGORY_ID = MACHINE_INTERVAL_ROW(indx).NPT_CATEGORY_ID;
SELECT S.SHIFT_NAME INTO SHIFT_NAME
FROM SHIFTS S
LEFT OUTER JOIN SHIFT_TBL STBL ON S.SHIFT_ID = STBL.SHIFT_NAME_FK
WHERE STBL.SHIFT_ID_PK = MACHINE_INTERVAL_ROW(indx).SHIFT_ID;
SELECT MACHINE_MODE_NAME INTO MACHINE_MODE
FROM MACHINE_MODE MM
WHERE MM.MACHINE_MODE_ID = MACHINE_INTERVAL_ROW(indx).MACHINE_MODE_ID;
SELECT JLS.JOB_LOAD_STATE_NAME INTO JOB_LOAD_STATE_NAME
FROM JOB_LOAD_STATE JLS
WHERE JLS.JOB_LOAD_STATE_ID = MACHINE_INTERVAL_ROW(indx).JOB_LOAD_STATE_ID;
--step five: merge record into test_machine_interval.
MERGE INTO TEST_MACHINE_INTERVAL TMI
USING (SELECT * FROM TEST_MACHINE_INTERVAL) OTMI
ON (TMI.MACHINE_INTERVAL_ID = OTMI.MACHINE_INTERVAL_ID)
WHEN MATCHED THEN
UPDATE SET TMI.MACHINE_INTERVAL_ID = OTMI.MACHINE_INTERVAL_ID, TMI.START_DATE_TIME = OTMI.START_DATE_TIME,
TMI.INTERVAL_DURATION = OTMI.INTERVAL_DURATION, TMI.CALC_END_TIME = OTMI.CALC_END_TIME,
TMI.MACHINE_NAME = OTMI.MACHINE_NAME, TMI.SITE_NAME = OTMI.SITE_NAME,
TMI.OPERATOR_INSTANCE = OTMI.OPERATOR_INSTANCE, TMI.OPERATOR_INSTANCE2 = OTMI.OPERATOR_INSTANCE2,
TMI.OPERATOR_INSTANCE3 = OTMI.OPERATOR_INSTANCE3, TMI.SHIFT_NAME = OTMI.SHIFT_NAME,
TMI.INTERVAL_CATEGORY = OTMI.INTERVAL_CATEGORY, TMI.NTP_CATEGORY_NAME = OTMI.NTP_CATEGORY_NAME,
TMI.MACHINE_MODE = OTMI.MACHINE_MODE, TMI.JOB_LOAD_STATE_NAME = OTMI.JOB_LOAD_STATE_NAME,
TMI.RAW_SOURCE_MSG_TYPE = OTMI.RAW_SOURCE_MSG_TYPE
WHEN NOT MATCHED THEN
INSERT (TMI.MACHINE_INTERVAL_ID, TMI.START_DATE_TIME, TMI.INTERVAL_DURATION, TMI.CALC_END_TIME,
TMI.MACHINE_NAME, TMI.SITE_NAME, TMI.OPERATOR_INSTANCE, TMI.OPERATOR_INSTANCE2,
TMI.OPERATOR_INSTANCE3, TMI.SHIFT_NAME, TMI.INTERVAL_CATEGORY, TMI.NTP_CATEGORY_NAME,
TMI.MACHINE_MODE, TMI.JOB_LOAD_STATE_NAME, TMI.RAW_SOURCE_MSG_TYPE )
VALUES (MACHINE_INTERVAL_ID, START_DATE_TIME, INTERVAL_DURATION, CALC_END_TIME,
MACHINE_NAME, SITE_NAME, OPERATOR_INSTANCE, OPERATOR_INSTANCE2, OPERATOR_INSTANCE3,
SHIFT_NAME, INTERVAL_CATEGORY, NTP_CATEGORY_NAME, MACHINE_MODE,
JOB_LOAD_STATE_NAME, RAW_SOURCE_MSG_TYPE);
/*
EXECUTE IMMEDIATE 'INSERT INTO TEST_MACHINE_INTERVAL
(MACHINE_INTERVAL_ID, START_DATE_TIME, INTERVAL_DURATION, CALC_END_TIME,
MACHINE_NAME, SITE_NAME, OPERATOR_INSTANCE, OPERATOR_INSTANCE2,
OPERATOR_INSTANCE3, SHIFT_NAME, INTERVAL_CATEGORY, NTP_CATEGORY_NAME,
MACHINE_MODE,JOB_LOAD_STATE_NAME,RAW_SOURCE_MSG_TYPE )
VALUES(:1, :2, :3, :4, :5, :6, :7, :8, :9, :10, :11, :12, :13, :14, :15)'
USING MACHINE_INTERVAL_ID, START_DATE_TIME, INTERVAL_DURATION,
CALC_END_TIME, MACHINE_NAME, SITE_NAME,
OPERATOR_INSTANCE, OPERATOR_INSTANCE2, OPERATOR_INSTANCE3,
SHIFT_NAME, INTERVAL_CATEGORY, NTP_CATEGORY_NAME,
MACHINE_MODE,JOB_LOAD_STATE_NAME,RAW_SOURCE_MSG_TYPE;
*/
END LOOP;
EXIT WHEN MACHINE_INTERVAL_ROW.COUNT = 0;
END LOOP;
END;
我 75% 确定我的问题在于我如何尝试获取上面代码中显示的批量集合。所以我的问题是:我应该如何从批量集合中获取值以用于数据合并?
非常感谢您的建议或 cmets。谢谢。
【问题讨论】:
【参考方案1】: 如果您使用FORALL
,则需要遵循一条SQL 语句,您将把整个集合传递给该语句。如果您只是想遍历集合中的元素,您可以使用FOR
循环。
引用集合的第 n 个元素的语法是 collection_name(index).column_name
。
所以,如果你想逐个迭代集合中的元素,你会想要类似
FOR indx IN MACHINE_INTERVAL_ROW.FIRST..MACHINE_INTERVAL_ROW.COUNT
LOOP
MACHINE_INTERVAL_ID := machine_interval_row(indx).MACHINE_INTERVAL_ID;
START_DATE_TIME := machine_interval_row(indx).START_DATE_TIME;
<<more code>>
END LOOP;
但是,如果您要重构代码,我不确定使用局部变量 MACHINE_INTERVAL_ID
而不是仅使用 machine_interval_row(indx).MACHINE_INTERVAL_ID
会带来什么好处。我也不确定你为什么要执行六个单独的 SELECT
语句,每个语句都返回一行,而不是编写一个 SELECT
语句将所有这些表连接在一起并填充你想要的任何局部变量。
您的MERGE
也会有问题——MERGE
的源和目标是同一个表是没有意义的——我希望您收到 Oracle 的错误如果它试图执行该语句,则无法生成一组稳定的行。您可以将查询的源更改为针对 DUAL
的查询,该查询选择了您填充的所有局部变量,我猜,即
MERGE INTO TEST_MACHINE_INTERVAL TMI
USING (SELECT machine_interval_row(indx).MACHINE_INTERVAL_ID,
machine_interval_row(indx).START_DATE_TIME
FROM dual) OTMI
ON (TMI.MACHIN_INTERVAL_ID = OTMI.MACHINE_INTERVAL_ID)
如果TEST_MACHINE_INTERVAL
一开始是空的,听起来你最好不要使用MERGE
,不要使用BULK COLLECT
,而只是写一个INSERT ... SELECT
来提取所有数据你想拉。类似的东西
INSERT INTO test_machine_interval( machine_interval_id,
start_date_time,
<<more columns>> )
SELECT machine_interval_id,
last_value(start_date_time) over (partition by machine_interval_id
order by start_date_time asc
rows between unbounded preceding
and unbounded following ) last_start_date_time,
<<more columns>>
FROM machine_interval
【讨论】:
生成一个选择语句然后插入结果是这个工具的原始版本。我正在使用批量收集/合并作为学习如何在实际练习中使用它们的一种方式,但是在阅读了您的回复并回顾了我要离开的示例之后,我现在看到他们在合并中使用了 2 个表.由于他们使用相似的表名,我猜我一定错过了。以上是关于ORA-38101: INSERT VALUES 子句中的列无效:的主要内容,如果未能解决你的问题,请参考以下文章
多个 INSERT 语句与具有多个 VALUES 的单个 INSERT
MySQL insert set 和 insert values
MySQL - 结合 INSERT、VALUES 和 SELECT?