Y
You may get into situation when you have added or enabled foreign key and it can't be activated because you have integrity issues. Here is a solution how to find these naugty rows.
First, create table for gathering results.
CREATE TABLE invalid_keys_tmp (
table_name VARCHAR2(128) NOT NULL,
column_name VARCHAR2(128) NOT NULL,
parent_table VARCHAR2(128) NOT NULL,
parent_column VARCHAR2(128 NOT NULL,
row_id ROWID NOT NULL,
--
CONSTRAINT pk_invalid_keys
PRIMARY KEY (table_name, column_name, row_id)
);
Check all tables for invalid keys, ignore NULL values. You may want to extend this for compound keys and maybe filter tables to not checking whole schema in single transaction.
BEGIN
DELETE FROM invalid_keys_tmp;
--
FOR c IN (
SELECT
fn.table_name AS foreign_table,
fc.column_name AS foreign_column,
pc.table_name AS parent_table,
pc.column_name AS parent_column
FROM user_constraints fn
JOIN user_constraints pn
ON pn.constraint_name = fn.r_constraint_name
JOIN user_cons_columns fc
ON fc.constraint_name = fn.constraint_name
JOIN user_cons_columns pc
ON pc.constraint_name = pn.constraint_name
LEFT JOIN user_cons_columns rc
ON rc.table_name = pc.table_name
AND rc.column_name = pc.column_name
AND rc.constraint_name != pc.constraint_name
AND rc.position = 1
WHERE fn.constraint_type = 'R'
AND fc.position = 1
AND pc.position = 1
ORDER BY 1, 2
) LOOP
EXECUTE IMMEDIATE
'INSERT INTO invalid_keys_tmp' ||
' SELECT' ||
' ''' || c.foreign_table || ''',' ||
' ''' || c.foreign_column || ''',' ||
' ''' || c.parent_table || ''',' ||
' ''' || c.parent_column || ''',' ||
' ROWID' ||
' FROM ' || c.foreign_table || ' f' ||
' WHERE ' || c.foreign_column || ' IS NOT NULL' ||
' AND NOT EXISTS (' ||
' SELECT ' || c.parent_column ||
' FROM ' || c.parent_table || ' p' ||
' WHERE p.' || c.parent_column || ' = f.' || c.foreign_column ||
' )';
END LOOP;
END;
/
Quick overview of gathered violations:
SELECT table_name, column_name, parent_table, parent_column, COUNT(0) AS invalid_rows FROM invalid_keys_tmp GROUP BY table_name, column_name, parent_table, parent_column ORDER BY table_name, column_name, parent_table, parent_column;
And here is a query which will show you the wrong rows in desired table.
SELECT *
FROM &TABLE_NAME
WHERE ROWID IN (
SELECT row_id
FROM invalid_keys_tmp
WHERE table_name = UPPER('&TABLE_NAME')
);
SELECT
'SELECT * FROM ' || LOWER(table_name) ||
' WHERE ROWID IN (' ||
' SELECT row_id FROM invalid_keys_tmp' ||
' WHERE table_name = ''' || table_name || '''' ||
');' AS q
FROM invalid_keys_tmp
GROUP BY table_name, column_name, parent_table, parent_column
ORDER BY table_name, column_name, parent_table, parent_column;
You may want to remove the table at the end.
DROP TABLE invalid_keys_tmp PURGE;
Comments
Post a Comment