Having NOT NULL constraints declared on columns that are genuinely not nullable not only is good practice, but can yield performance gains
Here's a little routine that lists those columns that don't have a NOT NULL constraint defined, and prints out 'alter table ... ' DDL for those columns that may need such a constraint defined (ie, there are currently no NOT NULL rows). It works across a nominated schema.
create or replace
procedure check_uncons_columns_for_null(
p_schema varchar2,
p_table_name varchar2 default null) is
cursor x is
select table_name, column_name,
max(column_name) over (partition by table_name ) as lastcol
from (
select a.table_name, a.column_name
from dba_tab_columns a
where a.owner = p_schema
and a.table_name = nvl(upper(p_table_name),a.table_name)
minus
select a.table_name, b.column_name
from dba_cons_columns b, dba_constraints a
where a.owner = p_schema
and a.constraint_type = 'C'
and a.table_name = nvl(upper(p_table_name),a.table_name)
and a.table_name = b.table_name
and a.owner = b.owner
and a.constraint_name = b.constraint_name
) order by 1,2;
str0 varchar2(32767);
str1 varchar2(32767);
str2 varchar2(32767);
str3 varchar2(32767);
prev varchar2(100) := '*';
cnt number;
trailer varchar2(5);
procedure do_sql(thesql varchar2) is
tcursor integer;
dummy integer;
begin
tcursor := dbms_sql.open_cursor;
dbms_sql.parse(tcursor,thesql,2);
dummy := dbms_sql.execute(tcursor);
dbms_sql.close_cursor(tcursor);
end;
begin
for i in x loop
if prev != i.table_name then
str0 := 'declare ';
str1 := 'begin select '; str2 := ' into ';
str3 := ' '; cnt := 1;
end if;
if i.column_name = i.lastcol then
trailer := ' ';
else
trailer := ','||chr(10);
end if;
str0 := str0 || 'v'||ltrim(cnt)||' number;';
str1 := str1 || 'sum(decode('||i.column_name||',null,1,0))'||trailer;
str2 := str2 || 'v'||ltrim(cnt)||trailer;
str3 := str3 || 'if v'||ltrim(cnt)||' = 0 then '||
'dbms_output.put_line(''alter table '||p_schema||'.'||i.table_name||
' modify ('||i.column_name||' not null);''); end if;'||chr(10);
if i.column_name = i.lastcol then
str2 := str2 ||' from '||p_schema||'.'||i.table_name||';';
str3 := str3 ||' end;';
do_sql(str0||' '||str1||' '||str2||' '||str3);
end if;
prev := i.table_name;
cnt := cnt + 1;
end loop;
end;