/

/

ERP Data Migration: SQL Queries You Need for a Smooth Transition

Content

ERP Data Migration: SQL Queries You Need for a Smooth Transition

ERP Data Migration: SQL Queries You Need for a Smooth Transition

ERP Data Migration: SQL Queries You Need for a Smooth Transition

Migrating from one ERP to another is one of the most complex projects a company undertakes. Whether you're moving from on-premise SAP to S/4HANA Cloud, from legacy systems to NetSuite, or from spreadsheets to your first ERP, data migration is where projects succeed or fail.

70% of ERP implementations experience significant delays. The number one cause? Data issues during migration.

These SQL queries help you avoid that fate.

The 4 Phases of ERP Data Migration

Phase

Goal

SQL Role

1. Assessment

Understand source data

Profiling, counting, sampling

2. Cleaning

Fix quality issues

Deduplication, standardization, null handling

3. Transformation

Map to target schema

Data type conversion, field mapping, lookups

4. Validation

Verify completeness

Record counts, checksum comparison, exception reports

Phase 1: Data Assessment Queries

Table Row Counts (Source Inventory)

SELECT 
    'customers' as table_name, COUNT(*) as row_count FROM customers
UNION ALL
SELECT 'vendors', COUNT(*) FROM vendors
UNION ALL
SELECT 'items', COUNT(*) FROM items
UNION ALL
SELECT 'sales_orders', COUNT(*) FROM sales_orders
UNION ALL
SELECT 'purchase_orders', COUNT(*) FROM purchase_orders
UNION ALL
SELECT 'gl_journal_entries', COUNT(*) FROM gl_journal_entries
UNION ALL
SELECT 'employees', COUNT(*) FROM employees
ORDER BY row_count DESC;

Data Quality Profile

Check for nulls, blanks, and invalid data in critical fields:

SELECT 
    COUNT(*) as total_customers,
    SUM(CASE WHEN email IS NULL OR email = '' THEN 1 ELSE 0 END) as missing_email,
    SUM(CASE WHEN phone IS NULL OR phone = '' THEN 1 ELSE 0 END) as missing_phone,
    SUM(CASE WHEN address_line1 IS NULL THEN 1 ELSE 0 END) as missing_address,
    SUM(CASE WHEN country IS NULL OR country = '' THEN 1 ELSE 0 END) as missing_country,
    SUM(CASE WHEN status NOT IN ('ACTIVE', 'INACTIVE', 'PROSPECT') THEN 1 ELSE 0 END) as invalid_status
FROM customers;

Date Range Analysis

Understand what historical data you're migrating:

SELECT 
    MIN(order_date) as earliest_order,
    MAX(order_date) as latest_order,
    COUNT(*) as total_orders,
    COUNT(DISTINCT customer_id) as unique_customers,
    COUNT(DISTINCT YEAR(order_date)) as years_of_data
FROM sales_orders;

Phase 2: Data Cleaning Queries

Find Duplicate Customers

SELECT 
    email,
    COUNT(*) as duplicate_count,
    GROUP_CONCAT(customer_id) as customer_ids,
    GROUP_CONCAT(customer_name) as names
FROM customers
WHERE email IS NOT NULL AND email != ''
GROUP BY email
HAVING COUNT(*) > 1
ORDER BY duplicate_count DESC;

Standardize Country Codes

SELECT DISTINCT country, COUNT(*) as records
FROM customers
WHERE country NOT IN ('US', 'UK', 'CA', 'DE', 'FR', 'AU', 'JP')
GROUP BY country
ORDER BY records DESC;

Clean Phone Number Formats

SELECT customer_id, phone,
    REGEXP_REPLACE(phone, '[^0-9+]', '') as cleaned_phone
FROM customers
WHERE phone IS NOT NULL
  AND phone REGEXP '[^0-9+() -]';

Remove Orphaned Records

-- Order lines without parent orders
SELECT ol.line_id, ol.order_id
FROM order_lines ol
LEFT JOIN sales_orders so ON ol.order_id = so.order_id
WHERE so.order_id IS NULL;

-- Invoices without customers
SELECT i.invoice_id, i.customer_id
FROM ar_invoices i
LEFT JOIN customers c ON i.customer_id = c.customer_id
WHERE c.customer_id IS NULL;

Phase 3: Data Transformation

Map Account Codes (Old Chart → New Chart)

SELECT 
    old.account_number as source_account,
    old.account_name as source_name,
    map.new_account_number as target_account,
    map.new_account_name as target_name,
    COALESCE(map.new_account_number, 'UNMAPPED') as mapping_status
FROM gl_accounts old
LEFT JOIN account_mapping map ON old.account_number = map.old_account_number
ORDER BY mapping_status DESC, old.account_number;

Transform Customer Data for Target Schema

SELECT 
    c.customer_id as legacy_id,
    UPPER(TRIM(c.customer_name)) as customer_name,
    LOWER(TRIM(c.email)) as email,
    REGEXP_REPLACE(c.phone, '[^0-9]', '') as phone_clean,
    COALESCE(c.country, 'US') as country,
    CASE c.status
        WHEN 'A' THEN 'ACTIVE'
        WHEN 'I' THEN 'INACTIVE'
        WHEN 'P' THEN 'PROSPECT'
        ELSE 'UNKNOWN'
    END as status_mapped,
    c.created_date,
    CURRENT_TIMESTAMP as migration_date
FROM customers c
WHERE c.status != 'DELETED';

Phase 4: Validation Queries

Record Count Comparison

SELECT 
    'customers' as entity,
    (SELECT COUNT(*) FROM source_db.customers WHERE status != 'DELETED') as source_count,
    (SELECT COUNT(*) FROM target_db.customers) as target_count,
    (SELECT COUNT(*) FROM source_db.customers WHERE status != 'DELETED') - 
    (SELECT COUNT(*) FROM target_db.customers) as difference;

Financial Balance Verification

-- Source system totals
SELECT 
    'SOURCE' as system,
    SUM(CASE WHEN entry_type = 'DEBIT' THEN amount ELSE 0 END) as total_debits,
    SUM(CASE WHEN entry_type = 'CREDIT' THEN amount ELSE 0 END) as total_credits
FROM source_db.gl_journal_lines
UNION ALL
-- Target system totals
SELECT 
    'TARGET',
    SUM(CASE WHEN entry_type = 'DEBIT' THEN amount ELSE 0 END),
    SUM(CASE WHEN entry_type = 'CREDIT' THEN amount ELSE 0 END)
FROM target_db.gl_journal_lines;

Find Migration Exceptions

-- Records that exist in source but not in target
SELECT s.customer_id, s.customer_name, s.email
FROM source_db.customers s
LEFT JOIN target_db.customers t ON s.customer_id = t.legacy_id
WHERE t.legacy_id IS NULL
  AND s.status != 'DELETED';

Common Migration Pitfalls

  • Character encoding: Special characters break during transfer. Always check for UTF-8 compatibility

  • Date formats: MM/DD/YYYY vs DD/MM/YYYY causes silent data corruption

  • Decimal precision: Financial amounts losing decimal places during conversion

  • Referential integrity: Foreign keys pointing to records that weren't migrated

  • Historical data volume: Decide how many years of history to migrate before you start

Let AI Write Your Migration Queries

Migration projects involve hundreds of queries. Data profiling, cleaning, transformation, validation. Each table, each field, each edge case.

AI2SQL accelerates this process. Describe what you need:

  • "Find all customers with duplicate email addresses"

  • "Map old account codes to new chart of accounts"

  • "Compare record counts between source and target databases"

Focus on the migration strategy. Let AI handle the SQL syntax. Try it free at ai2sql.io.

Share this

More Articles

More Articles

More Articles