How to drop all not null constraints from a DB2 table - sql

I would like to drop all not null constraints from all columns in a table in DB2 without having to specify each column name.
Ideally this would be a function, where I could pass a table name as a parameter. Going through sysibm.syscolumns to get the not null columns is perfectly fine.
Thanks!
EDIT:
A bit of background:
DB: DB2 LUW v11.1.0.0
OS: Linux, Debian (Debian 4.9.51-1 (2017-09-28)
I am creating a table from another table and need to import data into the newly created table. Unfortunately, the data to be imported sometimes does not have all the values which are needed for the not null columns, hence I have to remove all not null constraints before loading the data.
For Oracle, I have the following:
function f_remove_mandatory(p_tbname in varchar2) return boolean is
l_tbname all_tab_columns.table_name%type;
l_AltTabTxt varchar2(220);
cursor c_AlterDlTab (p_tablename in varchar2) IS
select column_name
from user_tab_columns
where table_name = p_tablename
and nvl(nullable,'x') = 'N';
begin
l_tbname := UPPER(p_tbname);
for c1 in c_AlterDlTab (l_tbname) loop
execute immediate 'ALTER TABLE ' || l_tbname ||' MODIFY ' || c1.column_name || ' NULL';
end loop;
return true;
exception when others then return false;
end;
And need something similar for DB2.

Related

REPLACE() in Postgres can't replace data

I'm new in postgres, I'm creating a procedure to rename table constraint names using the REPLACE(). If I test all the variables in this procedure the data is there and if I replace it manually it can. The problem is when this procedure is running the constraint name doesn't change.
create or replace procedure public.rename_existing_constraint_table(in table_name text, in date_now text, in list_constraint text[])
as $$ declare
const text;
table_rename text;
begin
table_rename := (select concat(table_name, '_', date_now));
if array_length(list_constraint, 1) >= 1 then
foreach const in array list_constraint loop
execute 'alter table if exists ' || table_name || ' RENAME CONSTRAINT ' || const || ' to ' || replace(const, table_name, table_rename);
end loop;
end if;
end $$
language plpgsql;
duplicate error because the data was not successfully renamed, it should be
app_devlogdetail_pkey to app_devlogdetail_20221214_pkey
psycopg2.errors.DuplicateTable: relation "app_devlogdetail_pkey" already exists
CONTEXT: SQL statement "alter table if exists app_devlogdetail_20221214 RENAME CONSTRAINT app_devlogdetail_pkey to app_devlogdetail_pkey"
PL/pgSQL function rename_existing_constraint_table(text,text,text[]) line 10 at EXECUTE
I have tried running the REPLACE() outside the procedure and it runs normally and the data can be changed, but when it is run inside the procedure to be executed the REPLACE() can't changed data. How to make the REPLACE() can run and the data can be changed or is there some other way around it?

Oracle procedure/function to create a trigger in table

I'm trying to create a procedure that given a table name, it will create a sequence and auto incrementing trigger, all using variables based on the table name.
Code :
CREATE OR REPLACE procedure CREATE_SEQUENTIAL_TR(table_name VARCHAR)
is -- Tried using declare but it wouldn't accept
coluna_cod varchar(100 char);
begin
--Finding the cod column name for this table first
--They start with "PK_CD"
select
COLUMN_NAME
into
coluna_cod
from
ALL_TAB_COLUMNS
where
TABLE_NAME=table_name
and COLUMN_NAME like "PK_CD%";
--Creating the sequence obj
drop sequence "cod" || table_name;
create sequence "cod" || table_name;
--Now creating the trigger
create or replace trigger "cod" || table_name || "tr"
before
UPDATE or INSERT on table_name
for each row
declare
cod number := coluna_cod;
tr_name varchar(100 char) := "cod" || table_name
begin
if UPDATING then
if :new.cod != :old.cod then
:new.cod := :old.cod;
end if;
else -- inserting
:new.cod := tr_name.nextval();
end if;
end;
end;
The complexity of this ended up quite out of the scope of my knowledge.
At the moment it is giving an error on drop sequence "cod" || table_name (Unexpected DROP symbol found) but I'm sure I have made other errors.
Can someone help me figure this logic out?
You can't put DDL statements (like drop or create or alter) directly inside a PL/SQL block. If you want to do DDL inside PL/SQL, you can do an execute immediate:
declare
begin
drop sequence X; -- error
execute immediate 'drop sequence X'; -- works fine
end;
/

Get Maximum Length allowed in column | Oracle

How to get the Max and Min length allowed in column of varchar2.
I have to test for incoming data from the temp table which is coming from some remote db. And each row value is to be tested for specific columns that it has maximum or minimum value which can be set into the column.
So I was to get the column specs using its schema details. I did make a proc for that:
PROCEDURE CHK_COL_LEN(VAL IN VARCHAR2,
MAX_LEN IN NUMBER :=4000,
MIN_LEN IN NUMBER :=0,
LEN_OUT OUT VARCHAR2)
IS
BEGIN
IF LENGTH(VAL)<MIN_LEN THEN
LEN_OUT := 'ERROR';
RETURN;
ELSIF LENGTH(VAL)>MAX_LEN THEN
LEN_OUT := 'ERROR';
RETURN;
ELSE
LEN_OUT := 'SUCCESS';
RETURN;
END IF;
END;
END CHK_COL_LEN;
But the problem is, it is not reusable and is a bit hardcoded. I have to explicitly send MAX and MIN value for each value along with the data to be checked.
So at the proc call, it's something like:
CHK_COL_LEN(EMP_CURSOR.EMP_ID, 5, 1, LEN_ERROR_MSG);
I instead want something like: (If something like this exist!)
CHK_COL_LEN(EMP_CURSOR.EMP_ID,
EMP.COLUMN_NAME%MAX_LENGTH,
EMP.COLUMN_NAME%MIN_LENGTH,
LEN_ERROR_MSG)
Thanks in advance.
EDIT
select max(length(col)) from table;
This is a solution, but again I will have to run this query each time to set the two variables for MAX and MIN value. And running extra two queries for each value and then setting 2 variables will cost be significant lose in performance when in have about 32 tables, each with 5-8 varchar2 columns and average rows of about 40k-50k in each table
You can query the table 'user_tab_columns table' to retrieve metadata information of a specific table:
SELECT
COLUMN_NAME, DATA_LENGTH, DATA_PRECISION
FROM
user_tab_columns
WHERE
t.table_name IN ('<YOURTABLE>');
with this information you can query the metadata directly in your stored procedure:
...
SELECT
CHAR_LENGTH INTO max_length
FROM
user_tab_columns
WHERE
table_name = '<YOURTABLE>' AND COLUMN_NAME = '<YOURCOLUMN>';
...
Exmple Procedure to get max length of table/column:
create or replace PROCEDURE GET_MAX_LENGTH_OF_COLUMN(
tableName IN VARCHAR2,
columnName IN VARCHAR2,
MAX_LENGTH OUT VARCHAR2)
IS
BEGIN
SELECT CHAR_LENGTH INTO MAX_LENGTH
FROM user_tab_columns
WHERE table_name = tableName AND COLUMN_NAME = columnName;
END GET_MAX_LENGTH_OF_COLUMN;
Try creating your procedure like this:
create or replace procedure Checking_size(column_name varchar2,columnvalue varchar2,state out varchar2) is
begin
execute immediate 'declare
z '||column_name||'%type;
begin
z:=:param2;
end;' using columnvalue;
state:='OK';
exception when value_error then
state:='NOT OK';
end;
As you can see i simulate an error assignment. If columnvalue length is bigger than the column i pass as column_name it will throws value_error exception and return NOT OK, else return OK.
For example, if your_table.your_column refer to a column with length (3) then return NOT OK.
declare
state varchar2(10);
begin
Checking_size('your_table.your_column','12345',state);
dbms_output.put_line(state);
end;
If the list of tables is not much you can specify the MIN Value using CHECK Constraint on the table.
Any DML on the table would automatically fail if it exceeds length assigned to that column.
CREATE TABLE suppliers
(
supplier_id numeric(4),
supplier_name varchar2(50),
CONSTRAINT check_supplier_id
CHECK (length(supplier_name) > 5 )
);

Is there a way to alter many tables to add default values to a common column name?

We have a set of 45 tables which carry a common column {variety}.
The need is to set all such columns with a default value {comedy}.
The ALTER TABLE (SCHEMA.TABLE_NAME) MODIFY(VARIETY DEFAULT 'COMEDY')
Will get it done, but I am wondering if there is a way to create a sql script in Oracle 11g that will change all tables within the schema which have a common coloumn name to the common default value.
DECLARE
cnt NUMBER;
BEGIN
FOR x IN (
SELECT DISTINCT t.table_name
FROM user_tables t
INNER JOIN user_tab_columns c ON c.table_name = t.table_name
) LOOP
EXECUTE IMMEDIATE 'ALTER TABLE (SCHEMA.' || x.table_name || ') MODIFY(VARIETY DEFAULT ''COMEDY'')';
END LOOP;
END;
The alter table statement can be written as following,
using alternate quoting mechanism.
'alter table ' || x.table_name || q'[ modify (variety default 'COMEDY')]'

generic stored procedure in oracle

I want to write a PLSQL stored procedure that accepts a table name as argument. This table is source table. Now inside my procedure i want to manipulate the fields of that table.
EX: I want to insert the records of this source table into another target table whose name is XYZ_<source table name>. The column names for source and target tables are the same. But there may be some extra fields in target table. How do i do it? The order of column names is not same.
You will have to build the INSERT statement dynamically.
create or replace procedure gen_insert
(p_src_table in user_tables.table_name%type
, p_no_of_rows out pls_integer)
is
col_str varchar2(16000);
begin
for rec in ( select column_name
, column_id
from user_tab_columns
where table_name = p_src_table
order by column_id )
loop
if rec.column_id != 1 then
col_str := col_str || ',' || rec.column_name;
else
col_str := rec.column_name;
end if:
end loop;
execute immediate 'insert into xyz_' || p_src_table || '('
|| col_str || ')'
|| ' select ' || col_str
|| ' from ' || p_src_table;
p_no_of_rows := sql%rowcount;
end;
/
Obviously you may want to include some error handling and other improvements.
edit
Having edited your question I see you have a special requirement for naming the target table which was obscured by the SO formatting.
You can do this using Dynamic SQL. Here's a link with basic info on Oracle Dynamic SQL