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. 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
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. 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
Edit3: Changes in merge query after discussion with 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.
You can add explicit null checks; 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 with nulls - initially fails, but works with explicit null checks added.
Another possibility is a data type mismatch, as you're using CHAR(15)
in the table you showed. 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. In that case, you can trim the CHAR
value:
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)
)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.