简体   繁体   English

ORACLE 12c唯一约束在MERGE命令中失败,该命令与索引中的所有列匹配

[英]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或NVARCHAR2Oracle就会使用未填充的比较语义” )和隐式转换在插入期间将导致约束冲突。 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)
    )

db<>fiddle 分贝<>小提琴

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM