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

标签 sql oracle merge

我有一个聚合数据表,这些数据收集不正确,我正在尝试将 select 的结果合并到其中,但我遇到了约束违规,并且可能遗漏了一些明显的东西。 表格很简单:

 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)

具有触发序列和触发器

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 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)
;

我收到错误: ORA-00001: 违反唯一约束 (DVRA_MONITORING.DVRA_STATS_AGG_HOURLY_UK1)

我在唯一约束中使用的相同列上进行匹配。我只插入不匹配的行,并且按相同的列进行分组,因此应该只有一行用于这些列的唯一组合。

当我执行此操作时,我只是一个更新表,因此在查询运行期间没有其他 session 操作数据。

我在这里缺少什么?

编辑:DVRA_STATS_AGG_HOURLY 中的数据已通过 insert into select 插入。与此合并中使用的相同选择。只是有些数据还没有正确加载,所以我正在修正。

编辑2:添加不为空

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)
;

最佳答案

如果您在 ON 子句中比较的四列中的任何一列为 null,那么它们将与您当前的条件不匹配,因为 null = null 未知。

您可以添加显式空检查;而不是:

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
    )

做类似的事情:

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 - 工作正常。

db<>fiddle with nulls - 最初失败,但可以使用添加的显式空检查。


另一种可能性是数据类型不匹配,因为您在显示的表中使用了 CHAR(15)。如果审计表将该列定义为 VARCHAR2(15) ,则比较也将失败(因为 "Oracle uses nonpadded comparison semantics whenever one or both values in the comparison have the data type VARCHAR2 or NVARCHAR2" ),并且插入期间的隐式转换将导致约束违规。在这种情况下,您可以修剪 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

关于sql - ORACLE 12c 唯一约束在 MERGE 命令中失败,该命令匹配索引中的所有列,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55265507/

相关文章:

php - 是否有用于生成迁移 SQL (postgres) 文件的脚本?

python - 从仅包含部分列数据的sqlite中检索行

sql - oracle中n维的曼哈顿距离

c++ - c++内存分配错误

c# - 将日期转换为正确的格式

sql - 为什么 DNN 中 DAL2 存储库的默认 GetById() 执行缓慢?

java - Hibernate 管理 @ManyToMany 表插入和订单

sql - 如何在WHERE子句中使用json列作为条件

python - Python 中联合多个嵌套 JSON

git - 如何将远程分支 merge 到本地分支?