Duplicate change orders created during ECN data migration, causing workflow confusion

We’re migrating 5 years of historical ECNs from our legacy PLM system to Agile 9.3.6 using SQL-based data import scripts. The migration is creating duplicate change orders for about 15% of our ECN records. When we query the database, we find multiple ECN records with the same legacy ID but different Agile-generated numbers.

The duplicates are causing major workflow issues because:

  • Some ECNs show up twice in affected items lists
  • Approval routing gets confused with multiple active ECNs for the same change
  • Reports show inflated change order counts

Our import script uses this approach:

INSERT INTO agile.change_orders
(legacy_id, number, description, status)
SELECT old_id, seq.nextval, desc, 'Pending'
FROM legacy_ecn_data;

We thought the legacy_id mapping would prevent duplicates, but we’re still seeing them. Has anyone dealt with duplicate prevention during large-scale ECN migrations? What’s the proper way to ensure unique identifier mapping during import?

I’ll walk you through a complete solution covering all three critical areas:

1. Unique Identifier Mapping Strategy

Your current approach has no duplicate prevention. Here’s the correct implementation:

Create Staging Table with Constraints:

CREATE TABLE ecn_staging (
  legacy_id VARCHAR2(50) PRIMARY KEY,
  agile_number VARCHAR2(50) UNIQUE,
  description VARCHAR2(500),
  status VARCHAR2(50),
  import_date DATE,
  is_processed CHAR(1) DEFAULT 'N'
);

Use MERGE Instead of INSERT:

MERGE INTO agile.change_orders dest
USING (SELECT * FROM ecn_staging WHERE is_processed = 'N') src
ON (dest.legacy_id = src.legacy_id)
WHEN NOT MATCHED THEN
  INSERT (legacy_id, number, description, status)
  VALUES (src.legacy_id, ecn_seq.nextval, src.description, src.status);

Key Mapping Principles:

  • Use legacy_id as natural key for duplicate detection
  • Create composite unique index on (legacy_id, revision) if ECNs have revisions
  • Map legacy status values to valid Agile workflow states
  • Preserve original ECN number in a custom attribute for reference
  • Use staging table to track what’s been processed

2. Pre-Import Deduplication Process

Before any import, clean your source data:

Step A: Identify Duplicates in Source

SELECT legacy_id, COUNT(*) as dup_count,
       MIN(creation_date) as first_created,
       MAX(creation_date) as last_created
FROM legacy_ecn_data
GROUP BY legacy_id
HAVING COUNT(*) > 1;

Step B: Deduplication Logic For your 8% source duplicates, establish rules:

  • If same legacy_id with different dates: Keep the latest (most recent revision)
  • If same legacy_id with different descriptions: Manual review required
  • If exact duplicates: Keep one, log the removal

Step C: Create Clean Source View

CREATE VIEW legacy_ecn_clean AS
SELECT legacy_id, description, status,
       ROW_NUMBER() OVER (PARTITION BY legacy_id ORDER BY creation_date DESC) as rn
FROM legacy_ecn_data
WHERE rn = 1;  -- Keep only latest version

Step D: Pre-Import Validation Script

# Validation before import
def validate_source_data():
    duplicates = check_duplicates()
    if duplicates > 0:
        log_error(f"Found {duplicates} duplicate legacy IDs")
        generate_duplicate_report()
        return False

    invalid_statuses = check_status_mapping()
    if invalid_statuses > 0:
        log_error(f"Found {invalid_statuses} unmapped statuses")
        return False

    return True

3. Post-Import Audit and Cleanup

Immediate Duplicate Detection:

-- Find duplicates created during import
SELECT legacy_id, COUNT(*) as duplicate_count,
       LISTAGG(number, ', ') as agile_numbers
FROM agile.change_orders
WHERE import_date >= TRUNC(SYSDATE)
GROUP BY legacy_id
HAVING COUNT(*) > 1;

Systematic Cleanup Process:

  1. Identify Keeper vs. Duplicate:
WITH ranked_ecns AS (
  SELECT change_id, legacy_id, number, creation_date,
         ROW_NUMBER() OVER (PARTITION BY legacy_id ORDER BY creation_date ASC) as rank
  FROM agile.change_orders
  WHERE legacy_id IS NOT NULL
)
SELECT * FROM ranked_ecns WHERE rank > 1;  -- These are duplicates to remove
  1. Handle Workflow Dependencies: Before deleting duplicates, check for:
  • Active workflow instances
  • Affected items relationships
  • Approval signatures
  • Document attachments
  1. Safe Deletion Approach:
-- First, reassign any affected items from duplicate to keeper
UPDATE affected_items
SET change_id = (SELECT MIN(change_id)
                 FROM agile.change_orders
                 WHERE legacy_id = :legacy_id)
WHERE change_id IN (SELECT change_id
                     FROM ranked_ecns
                     WHERE rank > 1 AND legacy_id = :legacy_id);

-- Then delete the duplicate
DELETE FROM agile.change_orders
WHERE change_id IN (SELECT change_id FROM ranked_ecns WHERE rank > 1);

4. Comprehensive Post-Import Audit Report

Generate documentation showing:

  • Total ECNs imported: 5000
  • Source duplicates resolved: 400 (8%)
  • Import duplicates prevented: 350 (7%)
  • Final duplicate count: 0
  • ECNs requiring manual review: 25

Prevention for Future Imports:

  1. Idempotent Import Script: Make your script safe to run multiple times:
CREATE OR REPLACE PROCEDURE import_ecns_safe AS
BEGIN
  -- Check if already imported
  IF EXISTS (SELECT 1 FROM import_log WHERE import_type = 'ECN' AND status = 'COMPLETE') THEN
    RAISE_APPLICATION_ERROR(-20001, 'ECN import already completed');
  END IF;

  -- Use MERGE for upsert behavior
  MERGE INTO agile.change_orders...

  -- Log completion
  INSERT INTO import_log VALUES ('ECN', SYSDATE, 'COMPLETE');
  COMMIT;
END;
  1. Add Unique Constraint:
ALTER TABLE agile.change_orders
ADD CONSTRAINT uk_legacy_id UNIQUE (legacy_id);
  1. Import Monitoring Dashboard: Track in real-time:
  • Records processed
  • Duplicates detected and skipped
  • Errors requiring attention
  • Estimated completion time

Fixing Your Current 15% Duplicate Issue:

  1. Run the duplicate detection query above
  2. Export list of all duplicates with their Agile numbers
  3. For each legacy_id with duplicates:
    • Keep the ECN with earliest creation_date (original import)
    • Transfer any unique data from duplicates to keeper
    • Update affected items to point to keeper
    • Delete duplicate records
  4. Add unique constraint to prevent future duplicates
  5. Re-run import script (now safe with MERGE logic) to catch any missed records

This approach will clean up your existing duplicates and prevent new ones. The key is making your import process idempotent so running it multiple times doesn’t create problems.


This draft is based on general Oracle Agile PLM knowledge. It has not been verified against your specific version and environment. Practitioners: verify the steps and share your experience below.

Your SQL is inserting every time without checking if the legacy_id already exists. You need a MERGE statement instead of INSERT, or add a WHERE NOT EXISTS clause to check for duplicates before inserting. Also, are you running the script multiple times? That would definitely create duplicates.

I’ve seen this pattern before. The issue is usually that your source data itself has duplicates that you’re not detecting. Run a duplicate check on your legacy_ecn_data table first - group by the fields that should be unique (legacy ID, description, creation date) and look for counts > 1. You might be migrating duplicates that already existed in the old system. Also, 15% is a high duplicate rate - suggests your import might be running multiple times or your source data has quality issues.

Good point about checking the source. I ran a duplicate check and found about 8% duplicates in the legacy data itself - mostly from ECNs that were revised or reissued. But that doesn’t explain the full 15% we’re seeing in Agile. The script has run twice (initial load plus one retry), which might explain some duplicates.

“Tested this on Oracle Agile PLM 9.3.6 migration and the MERGE statement with the ecn_staging UNIQUE constraint on agile_number eliminated all duplicate ECN records instantly.”

Running the script twice without duplicate prevention is definitely your problem. Each run creates new records because you’re using INSERT with sequence generation. You need to implement a three-phase approach: 1) Pre-import deduplication of source data, 2) Unique constraint or MERGE logic in your import script, 3) Post-import audit to catch any duplicates that slipped through. Also consider using Agile’s built-in import utilities instead of direct SQL - they have better duplicate handling.

For the workflow confusion issue, you need to address this immediately even while you fix the root cause. Run a query to identify all duplicate ECNs, then systematically close or obsolete the duplicates. Make sure you’re keeping the ‘correct’ version - usually the one with the earliest creation timestamp or the one with the most complete data. Document which records you’re removing so you can explain any audit trail gaps.