A
Another issue I faced on each project is data type inconsistency. In this older article I mentioned how to fix data types mismatches on keys. Today, I show you a script, which fix it for you (based on a column name match).
Let's explore this issue on the audit columns (who created or updated the row and when). To check the audit columns for user:
SELECT
c.column_name,
c.data_type,
c.char_used,
c.data_length,
c.nullable,
c.data_default_vc,
COUNT(*) AS count_tables
FROM user_tab_cols c
JOIN user_tables t
ON t.table_name = c.table_name
WHERE c.table_name LIKE '%'
AND c.column_name LIKE 'CREATED_BY'
GROUP BY
c.column_name,
c.data_type,
c.char_used,
c.data_length,
c.nullable,
c.data_default_vc
ORDER BY 1, 2, 3, 4;
Let's check the audit column for date. This gets more trickier, because we might not have consistent names. To keep the changes low, I am not changing the column names, just consolidating data types.
SELECT
c.column_name,
c.data_type,
c.char_used,
c.data_length,
c.nullable,
c.data_default_vc,
COUNT(*) AS count_tables
FROM user_tab_cols c
JOIN user_tables t
ON t.table_name = c.table_name
WHERE c.table_name LIKE '%'
AND c.column_name IN ('CREATED_ON', 'CREATED_AT')
GROUP BY
c.column_name,
c.data_type,
c.char_used,
c.data_length,
c.nullable,
c.data_default_vc
ORDER BY 1, 2, 3, 4;
So now you can see how good or bad is your project. If you have any inconsistencies, you can fix them with this script (modify part in the moddle for your data types):
BEGIN
FOR c IN (
SELECT
c.table_name,
c.column_name,
c.data_type,
c.char_used,
c.data_length,
c.nullable,
c.data_default_vc
FROM user_tab_cols c
JOIN user_tables t
ON t.table_name = c.table_name
WHERE c.table_name LIKE '%'
AND c.column_name IN ('CREATED_BY', 'CREATED_AT', 'CREATED_ON')
ORDER BY 1, 2
) LOOP
DBMS_OUTPUT.PUT_LINE('PROCESSING: ' || c.table_name || '.' || c.column_name);
-- disable table triggers
FOR d IN (
SELECT t.trigger_name
FROM user_triggers t
WHERE t.table_name = c.table_name
) LOOP
EXECUTE IMMEDIATE
'ALTER TRIGGER ' || d.trigger_name || ' DISABLE';
END LOOP;
-- we will be creating a column copy, so make sure we remove the one from previous run (if exists)
BEGIN
EXECUTE IMMEDIATE
'ALTER TABLE ' || c.table_name ||
' DROP COLUMN ' || c.column_name || '__';
EXCEPTION
WHEN OTHERS THEN
NULL;
END;
--
-- MODIFY THIS PART TO SET THE TYPE YOU WANT
--
IF c.column_name = 'CREATED_BY' THEN
EXECUTE IMMEDIATE
'ALTER TABLE ' || c.table_name ||
' ADD ' || c.column_name || '__ VARCHAR2(128) DEFAULT SYS_CONTEXT(''APEX$SESSION'',''APP_USER'')';
EXECUTE IMMEDIATE
'UPDATE ' || c.table_name ||
' SET ' || c.column_name || '__ = NVL(' || c.column_name || ', USER)';
END IF;
--
IF c.column_name IN ('CREATED_AT', 'CREATED_ON') THEN
EXECUTE IMMEDIATE
'ALTER TABLE ' || c.table_name ||
' ADD ' || c.column_name || '__ DATE DEFAULT SYSDATE';
EXECUTE IMMEDIATE
'UPDATE ' || c.table_name ||
' SET ' || c.column_name || '__ = NVL(' || c.column_name || ', SYSDATE)';
END IF;
-- make created* columns mandatory
IF c.column_name LIKE 'CREATED%' THEN
EXECUTE IMMEDIATE
'ALTER TABLE ' || c.table_name ||
' MODIFY ' || c.column_name || '__ NOT NULL';
END If;
-- remove original column, for big tables we should use UNUSED feature
EXECUTE IMMEDIATE
'ALTER TABLE ' || c.table_name ||
' DROP COLUMN ' || c.column_name;
--
EXECUTE IMMEDIATE
'ALTER TABLE ' || c.table_name ||
' RENAME COLUMN ' || c.column_name || '__ TO ' || c.column_name;
-- enable table triggers again
FOR d IN (
SELECT t.trigger_name
FROM user_triggers t
WHERE t.table_name = c.table_name
) LOOP
EXECUTE IMMEDIATE
'ALTER TRIGGER ' || d.trigger_name || ' ENABLE';
END LOOP;
END LOOP;
--
DBMS_UTILITY.COMPILE_SCHEMA(schema => USER);
END;
/
After you are done, you have to recompile invalid objects, sync your regions in APEX to update for new data types and you also might need to modify your audit triggers.
Comments
Post a Comment