[英]ORACLE 12c Unique constraint failing in MERGE command which is matching all columns from the index
I have a table of aggregated data which were collected incorrectly and I am trying to merge results of select into it and I am hitting constraint violation and probably missing something obvious. 我有一个汇总数据表,这些表收集不正确,并且我试图将select的结果合并到其中,但遇到约束违规并且可能缺少明显的东西。 Table is simple:
表很简单:
CREATE TABLE "DVRA_STATS_AGG_HOURLY"
( "ID" NUMBER(*,0),
"SHIPMENTS" NUMBER,
"EVENT_DATETIME" DATE,
"COUNTRY" VARCHAR2(2 CHAR),
"DATA_TYPE" VARCHAR2(3 CHAR),
"EVENT_TYPE" CHAR(15)
)
CREATE UNIQUE INDEX "DVRA_STATS_AGG_HOURLY_PK" ON "DVRA_STATS_AGG_HOURLY" ("ID")
CREATE UNIQUE INDEX "DVRA_STATS_AGG_HOURLY_UK1" ON "DVRA_STATS_AGG_HOURLY" ("EVENT_DATETIME", "COUNTRY", "DATA_TYPE", "EVENT_TYPE")
CREATE INDEX "DVRA_STATS_AGG_HOURLY_INDEX1" ON "DVRA_STATS_AGG_HOURLY" ("EVENT_DATETIME" DESC)
With trigger sequence and trigger 带触发顺序和触发
CREATE OR REPLACE EDITIONABLE TRIGGER "DVRA_STATS_AGG_HOURLY_AINC"
BEFORE INSERT ON dvra_stats_agg_hourly
FOR EACH ROW
BEGIN
SELECT stats_seq.NEXTVAL
INTO :new.id
FROM dual;
END;
Merge is not complicated either: 合并也不复杂:
MERGE INTO dvra_stats_agg_hourly stats
USING(
SELECT COUNT(*) as SHIPMENTS, TRUNC(event_datetime,'HH24') as event_datetime,COUNTRY,data_type,event_type
FROM AUDIT
WHERE event_type in (<List of events>)
and TRUNC(event_datetime,'HH24') < trunc(sysdate,'HH24')
and audittable.event_datetime is not null
and audittable.COUNTRY is not null
and audittable.data_type is not null
and audittable.event_type is not null
GROUP BY TRUNC(event_datetime,'HH24'),COUNTRY,data_type,event_type
) audittable
ON (
audittable.event_datetime = stats.event_datetime
and audittable.COUNTRY = stats.COUNTRY
and audittable.data_type = stats.data_type
and audittable.event_type = stats.event_type
)
WHEN MATCHED THEN
UPDATE SET stats.SHIPMENTS = audittable.SHIPMENTS WHERE stats.SHIPMENTS <> audittable.SHIPMENTS
WHEN NOT MATCHED THEN
INSERT (SHIPMENTS,event_datetime,STATS.COUNTRY,data_type,event_type)
VALUES (audittable.SHIPMENTS,audittable.event_datetime,audittable.COUNTRY ,audittable.data_type ,audittable.event_type)
;
And I am getting error: ORA-00001: unique constraint (DVRA_MONITORING.DVRA_STATS_AGG_HOURLY_UK1) violated 我收到错误消息:ORA-00001:唯一约束(DVRA_MONITORING.DVRA_STATS_AGG_HOURLY_UK1)被违反
I am matching on same columns as I am using in unique constraint. 我正在与在唯一约束中使用的相同列进行匹配。 I am inserting only not matching rows and I am grouping by same columns so there should be only one row for unique combination of those columns.
我只插入不匹配的行,并且按相同的列分组,因此这些列的唯一组合应该只有一行。
I am only one updating table when I am doing this operation, so no other session manipulating data during run of the query. 执行此操作时,我只是一个更新表,因此在运行查询期间没有其他会话在处理数据。
What am I missing here? 我在这里想念什么?
Edit: Data in DVRA_STATS_AGG_HOURLY were inserted with insert into select. 编辑:将DVRA_STATS_AGG_HOURLY中的数据与insert插入select中。 With same select which is used in this merge.
与此合并中使用的选择相同。 Just some data were not properly loaded yet, so I am making correction.
只是一些数据尚未正确加载,因此我正在更正。
Edit2: added not null Edit2:添加的不为null
Edit3: Changes in merge query after discussion with Alex Edit3:与Alex讨论后合并查询中的更改
MERGE INTO dvra_stats_agg_hourly stats
USING(
SELECT COUNT(*) as SHIPMENTS, TRUNC(event_datetime,'HH24') as event_datetime,COUNTRY,data_type,event_type
FROM BCTCUSTOM.V_DVRA_AUDIT
WHERE event_type in (<List of types>)
and TRUNC(event_datetime,'HH24') < trunc(sysdate,'HH24')
and TRUNC(event_datetime,'HH24') is not null
and event_datetime is not null
and COUNTRY is not null
and data_type is not null
and event_type is not null
GROUP BY TRUNC(event_datetime,'HH24'),COUNTRY,data_type,event_type
) audittable
ON (
audittable.event_datetime = stats.event_datetime
and ((audittable.COUNTRY is null and stats.COUNTRY is null) or audittable.COUNTRY = stats.COUNTRY)
and ((audittable.data_type is null and stats.data_type is null) or audittable.data_type = stats.data_type)
and ((audittable.event_type is null and stats.event_type is null) or audittable.event_type = stats.event_type)
)
WHEN MATCHED THEN
UPDATE SET stats.SHIPMENTS = audittable.SHIPMENTS WHERE stats.SHIPMENTS <> audittable.SHIPMENTS
WHEN NOT MATCHED THEN
INSERT (SHIPMENTS,event_datetime,STATS.COUNTRY,data_type,event_type)
VALUES (audittable.SHIPMENTS,audittable.event_datetime,audittable.COUNTRY ,audittable.data_type ,audittable.event_type)
;
If any of the four columns you are comparing in your ON
clause are null then they won't match with your current conditions, since null = null
is unknown. 如果您要在
ON
子句中比较的四列中的任何一列为null,则它们将与当前条件不匹配,因为null = null
是未知的。
You can add explicit null checks; 您可以添加显式null检查; instead of:
代替:
ON (
audittable.event_datetime = stats.event_datetime
and audittable.COUNTRY = stats.COUNTRY
and audittable.data_type = stats.data_type
and audittable.event_type = stats.event_type
)
do something like: 做类似的事情:
ON (
audittable.event_datetime = stats.event_datetime
and ((audittable.COUNTRY is null and stats.COUNTRY is null)
or audittable.COUNTRY = stats.COUNTRY)
and ((audittable.data_type is null and stats.data_type is null)
or audittable.data_type = stats.data_type)
and ((audittable.event_type is null and stats.event_type is null)
or audittable.event_type = stats.event_type)
)
db<>fiddle without nulls - works OK. db <> fiddle不包含null-工作正常。
db<>fiddle with nulls - initially fails, but works with explicit null checks added. db <>带有null的小提琴 -最初会失败,但可以使用添加的显式null检查。
Another possibility is a data type mismatch, as you're using CHAR(15)
in the table you showed. 另一种可能是数据类型不匹配,因为您在显示的表中使用的是
CHAR(15)
。 If the audit table has that column defined as VARCHAR2(15)
instead then the comparison will also fail (because "Oracle uses nonpadded comparison semantics whenever one or both values in the comparison have the data type VARCHAR2 or NVARCHAR2" ), and the implicit conversion during the insert will cause the constraint violation. 如果审核表将该列定义为
VARCHAR2(15)
则比较也会失败(因为“只要比较中的一个或两个值的数据类型为VARCHAR2或NVARCHAR2 , Oracle就会使用未填充的比较语义” )和隐式转换在插入期间将导致约束冲突。 In that case, you can trim the CHAR
value: 在这种情况下,您可以调整
CHAR
值:
ON (
audittable.event_datetime = stats.event_datetime
and audittable.COUNTRY = stats.COUNTRY
and audittable.data_type = stats.data_type
and audittable.event_type = trim(stats.event_type)
)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.