Posts tagged with “database”

Navigating Oracle Foreign Key Constraint Deletion: A Developer's Comprehensive Guide

Understanding the "Child Record Found" Dilemma

As an Oracle database developer, you've likely encountered the frustrating ORA-02292: integrity constraint violated - child record found error. This message appears when you attempt to delete a record from a parent table that is still referenced by child records in another table.

What Causes This Error?

Referential integrity constraints prevent you from deleting records that are crucial to maintaining data relationships. While these constraints protect your data's consistency, they can also complicate deletion processes.

Systematic Troubleshooting Approach

Step 1: Identify the Constraint

When you encounter the error, note the specific constraint name. In our example:

ERROR at line 1:
ORA-02292: integrity constraint (ACME_CORP.FK_TRANSACTION_ACCOUNT) violated

Step 2: Locate Referencing Constraints

Use the following comprehensive query to find details about the problematic constraint:

SELECT a.table_name, 
       a.constraint_name, 
       a.r_constraint_name,
       b.column_name
FROM all_constraints a
JOIN all_cons_columns b ON a.constraint_name = b.constraint_name
WHERE a.r_constraint_name = 'FK_TRANSACTION_ACCOUNT';

Step 3: Investigate Child Records

Once you've identified the referencing table, query the specific records:

SELECT b.*
FROM HR.EMPLOYEE_BANK_ACCOUNTS a
JOIN ACME_CORP.FINANCIAL_TRANSACTIONS b 
ON b.employee_bank_account_id = a.account_id
WHERE a.account_id IN (
    -- Your deletion criteria here
);

Resolution Strategies

Option 1: Cascade Delete

If appropriate for your data model, use ON DELETE CASCADE:

ALTER TABLE ACME_CORP.FINANCIAL_TRANSACTIONS 
DROP CONSTRAINT FK_TRANSACTION_ACCOUNT;

ALTER TABLE ACME_CORP.FINANCIAL_TRANSACTIONS 
ADD CONSTRAINT FK_TRANSACTION_ACCOUNT 
FOREIGN KEY (employee_bank_account_id)
REFERENCES HR.EMPLOYEE_BANK_ACCOUNTS(account_id)
ON DELETE CASCADE;

Option 2: Selective Deletion

Manually delete or update child records before removing parent records:

-- First, delete or update child records
DELETE FROM ACME_CORP.FINANCIAL_TRANSACTIONS 
WHERE employee_bank_account_id IN (
    SELECT account_id 
    FROM HR.EMPLOYEE_BANK_ACCOUNTS 
    WHERE deletion_condition
);

-- Then delete parent records
DELETE FROM HR.EMPLOYEE_BANK_ACCOUNTS 
WHERE deletion_condition;

Best Practices

  1. Always use transactions to ensure data consistency

  2. Understand your data relationships before modifying constraints

  3. Test deletion scripts in a staging environment

  4. Consider soft delete strategies for complex data models

ORA-12704: character set mismatch in case statement

I met this issue when I SELECT CASE WHEN d.COUNTRY != 'AU' THEN 'Australia' ELSE countries.NAME END

BTW, I asked ChatGPT for help about this issue but unfortunately I didn't get a good answer.
One of the correct answers was

SELECT CASE WHEN d.COUNTRY != 'AU' THEN 'Australia' ELSE TO_CHAR(countries.NAME) END ...

I found the above answer myself and I told ChatGPT this answer. It replied

Great to hear that you were able to solve the issue! Yes, you can use the TO_CHAR function to convert the character set of the countries.NAME column to match the character set of your database. This is a common solution for character set mismatch errors. Using TO_CHAR function, you can explicitly specify the character set you want to convert to, like this:

TO_CHAR(countries.NAME, 'NLS_CHARACTERSET')

where 'NLS_CHARACTERSET' is the character set of your database. By default, Oracle uses the database's character set for character data that has no specified character set, so if you don't specify a character set for TO_CHAR, it will use the database's character set.

another answer is to use the CAST function in PL/SQL, here's an example from stackoverflow.com

Keep the the same order as input data when using `WHERE fieldName IN(fieldVal1, fieldVal2)`

Don't waste time; here's the sample code with the Oracle database.

SELECT * FROM SampleTable WHERE sample_field in (7,3,4,6) ORDER BY INSTR(',7,3,4,6,',  ',' || sample_field || ',');

MySQL IF(EXPRESSION, A, B) equivalent in PL/SQL (Oracle)

In MySQL, we can

SELECT IF(A IS NULL, "something", A) FROM some_table;

If you want to do a similar thing in PL/SQL, you need to

SELECT (CASE WHEN A IS NULL THEN "something" ELSE A END) FROM some_table;

If you want to get the first non-null value from several fields, you have a better choice than using the CASE keyword.

SELECT COALESCE(A, B) FROM some_table

see more information about the Oracle COALESCE function

CTE 101

Today I first learnt the concept of CTE (Common Table Expression) from my colleague Rod. Basically, CTE can be used to improve the readability of your long and complex SQL statement.

for example, without CTE, you might write the following SQL:

CREATE OR REPLACE VIEW dfx.test_vw123 AS
SELECT 
	a.FIELD_A, 
	a.FIELD_B, 
	b.FIELD_C
	b.FIELD_D
FROM (
	SELECT 
		MAX(FIELD_A) AS FIELD_A, 
		COUNT(*) AS FIELD_B 
	FROM TABLE_A ta 
	WHERE ta.FIELD_E = 'General' 
	GROUP BY ta.FIELD_F
) a 
LEFT JOIN TABLE_A b 
ON a.FIELD_A = b.FIELD_A

with CTE, you could write the following one with better readability.

CREATE OR REPLACE VIEW dfx.test_vw123 AS
WITH TABLE_A_STATS AS (
	SELECT 
		MAX(FIELD_A) AS FIELD_A, 
		COUNT(*) AS FIELD_B 
	FROM TABLE_A ta 
	WHERE ta.FIELD_E = 'General' 
	GROUP BY ta.FIELD_F
)
SELECT 
	a.FIELD_A, 
	a.FIELD_B, 
	b.FIELD_C
	b.FIELD_D
FROM TABLE_A_STATS a 
LEFT JOIN TABLE_A b 
ON a.FIELD_A = b.FIELD_A;

For further information about CTE, click Reference
I also found another article about CTE in Chinese.