how to create SQL procedure which contains compile time errors? - db2

I am writing a one time SQL procedure which will add an identity column to a table, then set the primary key of the table to that new identity column. But I cannot compile the SQL procedure because the CREATE PROCEDURE statement returns a compile error.
How to tell SQL to create the procedure despite the compile error?
CREATE or replace PROCEDURE TESTSQL(
)
LANGUAGE SQL
SPECIFIC ORDHEADP5T
SET OPTION DATFMT = *ISO, DLYPRP = *YES, DBGVIEW = *SOURCE,
USRPRF = *OWNER, DYNUSRPRF = *OWNER, COMMIT = *CHG
BEGIN
alter table ordheader
add column ordidnum int generated always as identity ;
alter table ordheader
add constraint pk_ordheader primary key ( ordidnum ) ;
end
SQL0205 30 14 Position 44 Column ORDIDNUM not in table ORDHEADER

You can do this one if you reduce it to one alter table like :
CREATE or replace PROCEDURE TESTSQL()
LANGUAGE SQL
SPECIFIC ORDHEADP5T
SET OPTION DATFMT = *ISO, DLYPRP = *YES, DBGVIEW = *SOURCE,
USRPRF = *OWNER, DYNUSRPRF = *OWNER, COMMIT = *CHG
BEGIN
alter table ordheader
add column ordidnum int generated always as identity
add constraint pk_ordheader primary key ( ordidnum ) ;
end

Related

How to use JSONB_SET for updating JSONB Column in PostgreSQL Procedure

I am using a Stored Procedure to update a JSONB column in the table and it does not seem to work. Any help would be much appreciated. Many Thanks.
My Table is:
CREATE TABLE mn_customer (
cust_id int,
f_name varchar(20),
l_name varchar(20),
json_payload jsonb);
My SPROC is:
create or replace procedure update_mn_customer
(
update_cust_id int DEFAULT null,
update_json_payload jsonb DEFAULT null
)
language plpgsql as
$proc$
begin
update mn_customer
set json_payload = jsonb_set(json_payload, update_json_payload)
where cust_id = update_cust_id;
commit;
end
$proc$;
My call to procedure to perform an Update is:
call update_mn_customer(
1998, to_jsonb('{"jsonpayload-fld1": "John Davis", "jsonpayload-fld2": "Lenny Pascoe","jsonpayload-fld3": "Undefined"}'::text)
);
I keep getting the Error:
ERROR: function jsonb_set(jsonb, jsonb) does not exist
LINE 2: set json_payload = jsonb_set(json_payload, update_js...
^
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
QUERY: update mn_customer
set json_payload = jsonb_set(json_payload, update_json_payload)
where cust_id = update_cust_id
CONTEXT: PL/pgSQL function update_mn_customer(integer,jsonb) line 8 at SQL statement
You use jsonb_set when you want to replace only one part of the jsonb data identified by a path with a new jsonb value. In your case, it seems that update_json_payload is the new value for the json_payload column so you just have to update it :
update mn_customer
set json_payload = update_json_payload
where cust_id = update_cust_id ;
Then you don't need to commit inside the plpgsql procedure.

Multiple table modification(same table has been used in that function) inside the Postgresql function

create or replace function report(IN rows_count numeric DEFAULT 1000,
OUT out_rc_type rc_type)
RETURNS rc_type
AS
DECLARE
BEGIN
PERFORM ddl_exec_pkg.ddl_execute ( 'ALTER TABLE REPORT_UI DROP CONSTRAINT REPORT_ID');
PERFORM ddl_exec_pkg.ddl_execute ( 'ALTER TABLE REPORT_ALL_UI DROP CONSTRAINT REPORT_ID');
INSERT INTO
REPORT_UI (SELECT * FROM GE_REPORT);
PERFORM ddl_exec_pkg.ddl_execute ('ALTER TABLE REPORT_UI ADD CONSTRAINT REPORT_ID CHECK (1 = 1)');
PERFORM ddl_exec_pkg.ddl_execute ('ALTER TABLE REPORT_ALL_UI ADD CONSTRAINT REPORT_ID CHECK (1 = 1)');
END;
When in run the above code I am getting below error:
ERROR: cannot ALTER TABLE "REPORT_UI "
because it is being used by active queries in this session CONTEXT:
SQL statement "ALTER TABLE REPORT_UI ADD
CONSTRAINT REPORT_ID CHECK (1 = 1)"

how to create a column constant in Postgresql

create table test(
t_id SERIAL primary key,
t_date CONSTANT date default CURRENT_DATE
);
ERROR: syntax error at or near "date"
LINE 3: t_date CONSTANT date default CURRENT_DATE
^
********** Error **********
ERROR: syntax error at or near "date"
SQL state: 42601
For a default value you can use a function,
CREATE TABLE test(
t_id SERIAL primary key,
t_date date DEFAULT now()
);
about constant, I never used, even other SQL (!), only in a PL/SQL context ...
If you need a "no update" constraint, you can use a trigger. Example:
CREATE FUNCTION correct_update() RETURNS trigger AS $$
BEGIN
NEW.t_date=OLD.t_date;
RETURN NEW;
END
$$ LANGUAGE plpgsql;
CREATE TRIGGER no_date_update
BEFORE BEFORE UPDATE ON test
FOR EACH ROW
WHEN (OLD.t_date IS DISTINCT FROM NEW.t_date)
EXECUTE PROCEDURE correct_update();
For a complete control, you need also trigg the INSERT event, (and does not need a default value anymore because insert trigger will do):
create table test(
t_id SERIAL primary key,
t_date date -- a default will be redundant
);
CREATE FUNCTION correct_date() RETURNS trigger AS $$
BEGIN
IF TG_OP = 'INSERT' THEN
NEW.t_date=now(); -- default value
ELSIF TG_OP = 'UPDATE' THEN -- optional AND OLD.t_date != NEW.t_date
NEW.t_date=OLD.t_date; -- "constant" behaviour
END IF;
RETURN NEW;
END
$$ LANGUAGE plpgsql;
CREATE TRIGGER constant_date
BEFORE INSERT OR UPDATE ON test
FOR EACH ROW
EXECUTE PROCEDURE correct_date();
The OLD.t_date != NEW.t_date comparison is optional, because not affects performance... But is a good practice to use it. Another way is to check in the trigger, by WHEN, but only update triggers can use OLD... So, the best create-triggers for the same correct_date() function (with no old/new comparison) are:
CREATE TRIGGER constant_date_ins
BEFORE INSERT ON test
FOR EACH ROW
EXECUTE PROCEDURE correct_date();
CREATE TRIGGER constant_date_upd
BEFORE UPDATE ON test
FOR EACH ROW
WHEN (OLD.t_date IS DISTINCT FROM NEW.t_date)
EXECUTE PROCEDURE correct_date();
Contextualizing in a scenario
As commented above in the question, there are a lack of contextualization , ex. explaining "why you think this should work and what it should do".
Scenario-1: the db-master need to block careless programmers
We can imagine a framework like CakePHP with a "created" field and a database-master that wants that this field have a "constant behaviour", preventing that careless programmers affects this "expected constraint".
That kind of scenario was used in the anwser.
Scenario-2: the project decision is to alert by error
This is the suggestion #IgorRomanchenko ...
... now here as a Wiki, you can EDIT and add new solution/example ...
You want a check constraint
create table test(
t_id SERIAL primary key,
t_date date default CURRENT_DATE check(t_date = current_date)
);
insert into test(t_date) values (default);
INSERT 0 1
insert into test(t_date) values ('2014-01-01');
ERROR: new row for relation "test" violates check constraint "test_t_date_check"
DETAIL: Failing row contains (2, 2014-01-01).
Or may be a foreign key constraint which allows multiple possible values and can be updated without altering the table's schema
create table date_constraint (
date_constraint date primary key
);
insert into date_constraint (date_constraint) values (current_date);
create table test(
t_id SERIAL primary key,
t_date date
default CURRENT_DATE
references date_constraint(date_constraint)
);
insert into test(t_date) values (default);
INSERT 0 1
insert into test(t_date) values ('2014-01-01');
ERROR: insert or update on table "test" violates foreign key constraint "test_t_date_fkey"
DETAIL: Key (t_date)=(2014-01-01) is not present in table "date_constraint".
http://www.postgresql.org/docs/current/static/ddl-constraints.html

db2 create procedure using razor

I am using RazorSQL tool to work with DB2. I try to create procedure which contains if table not exist statement.
the problem I am having is that if table doesn't exist it procedure has to execute create table statements.
trying co create a procedure returns error (syntax error), like it can not execute more then only create table statement.
example:
CREATE PROCEDURE KLEMENTEST.create_table
()
LANGUAGE SQL
MODIFIES SQL DATA
--READS SQL DATA
--CONTAINS SQL
begin atomic
if (not exists(select 'A' from syscat.tables where tabschema = 'KLEMENTEST' and tabname='bendeldoba')) then
create table klementest.bendeldoba (
bdd_id_bdd INTEGER not null,
bdd_naziv VARCHAR(128) not null,
bdd_mesecev INTEGER not null default 0,
bdd_prispevki INTEGER,
bdd_procent numeric,
bdd_racuni INTEGER,
bdd_datvpisa DATE not null,
bdd_vpisal_uporabnik INTEGER not null default 0
);
alter table klementest.bendeldoba add constraint P_Key_1 primary key (bdd_id_bdd);
end if;
end
alter table is causing the problems. If I comment it it works, also trying co execute smth like
CREATE PROCEDURE KLEMENTEST.create_table
()
LANGUAGE SQL
MODIFIES SQL DATA
--READS SQL DATA
--CONTAINS SQL
begin atomic
if (not exists(select 'A' from syscat.tables where tabschema = 'KLEMENTEST' and tabname='bendeldoba')) then
crete view def_schema.view1 as select * from sometable;
crete view def_schema.view2 as select * from someothertable;
end if;
end
it works
where is the "syntax error" problem with my first create procedure query??
thank you
In DB2, SQL stored procedures are bound statically in the database. This means that any static SQL statements (i.e. ones that you don't execute using PREPARE/EXECUTE or EXECUTE IMMEDIATE) will be checked and compiled when you create the stored procedure.
Therefore, the error occurs because when DB2 checks the ALTER TABLE statement to validity, the KLEMENTEST.BENDELDOBA does not yet exist.
The best way to resolve this is to make the ALTER TABLE statement a dynamic statement:
declare vSQL varchar(1024);
-- portion of procedure that creates the table...
set vSQL = 'alter table ...';
execute immediate vSQL;
I had to add some additional "setters", to declare where atomic procedure starts and ends
The code looks like this now
CREATE PROCEDURE KLEMENTEST.create_table
()
LANGUAGE SQL
ap: begin atomic
declare vsql varchar(1024) ;
set vSQL = 'alter table KLEMENTEST.avtvrsteplacilapod add constraint P_Key_1 primary key (avp_id_avp)';
if (not exists(select 'A' from syscat.tables where tabschema = 'KLEMENTEST' and tabname='AVTVRSTEPLACILAPOD')) then
create table KLEMENTEST.avtvrsteplacilapod (
avp_id_avp INTEGER not null,
avp_vrsteplacila INTEGER not null,
avp_naziv VARCHAR(64) not null,
avp_skupinevrpl INTEGER not null ,
avp_avtvrplmestovprog INTEGER ,
avp_postrm SMALLINT not null,
avp_upostzap SMALLINT not null
);
execute immediate vsql;
end if ;
end ap

Firebird 2.5 - add unique ID to each row in a table from stored procedure

I have a table which doesn't have an unique ID. I want to make a stored procedure which is adding to each row the number of the row as ID, but I don't know how to get the current row number. This is what I have done until now
CREATE OR ALTER PROCEDURE INSERTID_MYTABLE
returns (
cnt integer)
as
declare variable rnaml_count integer;
begin
/* Procedure Text */
Cnt = 1;
for select count(*) from MYTABLE r into:rnaml_count do
while (cnt <= rnaml_count) do
begin
update MYTABLE set id=:cnt
where :cnt = /*how should I get the rownumber here from select??*/
Cnt = Cnt + 1;
suspend;
end
end
I think better way will be:
Add new nullable column (let's call it ID).
Create a generator/sequence (let's call it GEN_ID).
Create a before update/insert trigger that fetches new value from sequence whenever the NEW.ID is null. Example.
Do update table set ID = ID. (This will populate the keys.)
Change the ID column to not null.
A bonus. The trigger can be left there, because it will generate the value in new inserted rows.