Get part of the query from a text column - sql

Suppose i have a text column in some table. I can select a value from this column with
(SELECT textcolumn from sometable WHERE ....) and query result will be '5>3'.
Now i want to add this result to my other query.
UPDATE someothertable SET somecolumn WHERE (SELECT textcolumn from sometable WHERE ....)
I want this to act like
UPDATE someothertable SET somecolumn WHERE 5>3
How can i do this in postgresql?

smth like:
do
$$
begin
execute format('UPDATE someothertable
SET somecolumn
WHERE %s',(SELECT textcolumn from sometable WHERE ....));
end;
$$
;
example:
t=# create table ta(i int);
CREATE TABLE
t=# create table tb(t text);
CREATE TABLE
t=# insert into ta select 1;
INSERT 0 1
t=# insert into tb select 'i < 9';
INSERT 0 1
t=# do
$$
begin
execute format('UPDATE ta
SET i = 2
WHERE %s',(SELECT t from tb));
end;
$$
;
DO
t=# select * from ta;
i
---
2
(1 row)
I don't think this is a good idea though...

Related

ORACLE update with returning OLD and NEW values

Is there equivalent to this T-SQL query in PL/SQL (Oracle 12c)?
UPDATE A SET A.columnA = 10 WHERE A.columnB < 30 OUTPUT INSERTED.*, DELETED.*
The query updates table A and at the same time returns the status of the record before the update and after the update.
Trigger is not a solution for me as well as SELECT records before and SELECT records after updating.
Not a direct one, but using RETURNING INTO you will be able to achieve the same effect:
CREATE TABLE A(columnA VARCHAR2(10), columnB INT);
INSERT INTO A(columnA, columnB) VALUES ('Test', 10);
INSERT INTO A(columnA, columnB) VALUES ('Row 2', 20);
CREATE TABLE audit_table(col_new VARCHAR2(10),col_old VARCHAR2(10));
DECLARE
TYPE rec IS RECORD (actual A.columnA%TYPE, old A.columnA%TYPE);
TYPE col_a_t IS TABLE OF rec;
v_a col_a_t;
BEGIN
UPDATE (SELECT A.*, (SELECT A.columnA FROM dual) AS old_columnA FROM A)
SET columnA = 'XYZ'
WHERE columnB < 30
RETURNING columnA, old_columnA BULK COLLECT INTO v_a;
COMMIT;
-- printing for debug
FOR i IN v_a.first .. v_a.last LOOP
dbms_output.put_line('Old =>' || v_a(i).old || ' new => ' || v_a(i).actual);
END LOOP;
-- additional
FORALL i IN v_a.first .. v_a.last
INSERT INTO audit_table VALUES v_a(i);
COMMIT;
END;
/
SELECT * FROM A;
SELECT * FROM audit_table;
DBFiddle Demo
Idea taken from: Returning Old value during update

How to create function that updates changes in one table from another table?

I have this function that I found here:
Insert trigger to Update another table using PostgreSQL
CREATE TABLE table1
(
id integer NOT NULL,
name character varying,
CONSTRAINT table1_pkey PRIMARY KEY (id)
)
CREATE TABLE table2
(
id integer NOT NULL,
name character varying
)
CREATE OR REPLACE FUNCTION function_copy() RETURNS TRIGGER AS
$BODY$
BEGIN
INSERT INTO
table2(id,name)
VALUES(new.id,new.name);
RETURN new;
END;
$BODY$
language plpgsql;
CREATE TRIGGER trig_copy
AFTER INSERT ON table1
FOR EACH ROW
EXECUTE PROCEDURE function_copy();
If I insert these two rows:
insert into table1 values (1, 'Andrey');
insert into table1 values (2, 'Mariza');
Then they also go into table2.
My problem is when I do an update on a value:
update table1 set name = 'Andi' where id = '1';
nothing happens in table2.
How can I create a function that updates changes in table?
To support UPDATE you can do this:
Trigger:
CREATE TRIGGER trig_copy
AFTER INSERT OR UPDATE ON table1
FOR EACH ROW
EXECUTE PROCEDURE function_copy();
Function:
CREATE OR REPLACE FUNCTION function_copy() RETURNS TRIGGER AS
$BODY$
BEGIN
if TG_OP='INSERT' then
INSERT INTO table2(id,name) VALUES(new.id,new.name);
end if;
if TG_OP='UPDATE' then
Update table2 set name=new.name where id=old.id;
end if;
RETURN new;
END;
$BODY$
language plpgsql;
create or replace trigger trig_copy
after insert or update
on table1
begin
merge into table2 t2
using (
select
id,
name
from
table1 t1) t_new
on (t2.id = t_new.id)
when matched then
update
set
t2.name = t_new.name
where
t2.id = t_new.id
WHEN NOT MATCHED then
insert (id,name) values(t_new.id,t_new.name);
end;
This will be applied to all records, not only updated record.
If U want to update/insert only one record Create trigger
referencing new as new
for each row
and use :new.id :new.name , to find record You want in t2.
Thanks to all for help. This is the answer that had worked for me.
I took it from Elads and Justas solutions:
CREATE TRIGGER trig_copy
AFTER INSERT OR UPDATE ON table1
FOR EACH ROW
EXECUTE PROCEDURE function_copy();
CREATE OR REPLACE FUNCTION function_copy() RETURNS TRIGGER AS
$BODY$
BEGIN
if TG_OP='INSERT' then
INSERT INTO table2
(SELECT * FROM table1
WHERE id NOT IN
(SELECT id FROM table2));
end if;
if TG_OP='UPDATE' then
Update table2 set name=new.name where id=old.id;
end if;
RETURN new;
end;
$BODY$
language plpgsql;

Create procedure for inserting the records, if exception, procedure needs start from exception line

I need to write the procedure for inserting the records in to multiple tables, for example I have 3 table,
CREATE TABLE SOURCE
(
SORT_CODE NUMBER,
FLAG CHAR(1)
);
INSERT INTO SOURCE VALUES(605096,5);
INSERT INTO SOURCE VALUES(605097,5);
INSERT INTO SOURCE VALUES(605098,5);
INSERT INTO SOURCE VALUES(605099,5);
INSERT INTO SOURCE VALUES(605100,5);
INSERT INTO SOURCE VALUES(605101,6);
INSERT INTO SOURCE VALUES(605102,6);
INSERT INTO SOURCE VALUES(605103,6);
INSERT INTO SOURCE VALUES(605104,6);
INSERT INTO SOURCE VALUES(605105,6);
SQL> SELECT * FROM SOURCE;
SORT_CODE F
---------- -
605096 5
605097 5
605098 5
605099 5
605100 5
605101 6
605102 6
605103 6
605104 6
605105 6
10 rows selected.
CREATE TABLE TARGET
(
SORT_CODE NUMBER,
TARGET_SORT_CODE NUMBER
);
Table created.
INSERT 5 VALUES
INSERT INTO TARGET VALUES(605101,189873);
INSERT INTO TARGET VALUES(605102,189874);
INSERT INTO TARGET VALUES(605103,189875);
INSERT INTO TARGET VALUES(605104,189876);
INSERT INTO TARGET VALUES(605105,'');
SELECT * FROM TARGET;
SORT_CODE TARGET_SORT_CODE
---------- ----------------
605101 189873
605102 189874
605103 189875
605104 189876
605105
CREATE TABLE NEWID
(
SORT_CODE NUMBER,
ID_SCODE NUMBER
);
Table created.
INSERT 2 VALUES
INSERT INTO TARGET VALUES(605103,189875);
INSERT INTO TARGET VALUES(605104,189876);
SELECT * FROM NEWID;
SORT_CODE ID_SCODE
---------- ----------------
605103 189875
605104 189876
Creating intermediate tables with existing table's structure.
CREATE TABLE SOURCE_TEMP AS (SELECT * FROM SOURCE WHERE 1=2);
CREATE TABLE TARGET_TEMP AS (SELECT * FROM TARGET WHERE 1=2);
CREATE TABLE NEWID_TEMP AS (SELECT * FROM NEWID WHERE 1=2);
My Procedure for inserting the records
CREATE OR REPLACE PROCEDURE insert_sql
is
BEGIN
DELETE FROM SOURCE_TEMP;
INSERT INTO SOURCE_TEMP SELECT * FROM SOURCE; --insert query 1
DELETE FROM TARGET_TEMP;
INSERT INTO TARGET_TEMP SELECT * FROM TARGET; --insert query 2
--due to some network issue or table error this procedure GOT EXEPCTION here and above insert query 2(TARGET_TEMP) and below --insert query 3(NEWID_TEMP) is not inserted the values or not executed procedure is came out from this line.
DELETE FROM NEWID_TEMP;
INSERT INTO NEWID_TEMP SELECT * FROM NEWID; --insert query 3
EXCEPTION
WHEN NO_DATA_FOUND THEN DBMS_OUTPUT.PUT_LINE('ERROR');
END;
Point 1: The above procedure is executed only one insert query 1 SOURCE_TEMP is got the values.
Point 1: TARGET_TEMP and NEWID_TEMP is not inserted the values or not execute.
My question: can I re-execute this procedure with starting point of '--insert query 2' line?
because I am inserting the 100 tables records in new tables, if 50 tables are inserted the values during this time if I am getting any error in the proc execution, remaining 50 tables needs to insert the values, for I don't wish to delete the previous 50 tables inserted the values it will be the time consuming activity. Any save point or boolean concepts is there for this type of issue in ORACLE (which is available in java and unix). if yes how to use this function?
CREATE OR REPLACE PROCEDURE insert_sql
is
v_new_rec_count int:=0;
BEGIN
select count(*)
into v_new_rec_count
from (
select * FROM SOURCE
minus
select * FROM SOURCE_TEMP
) ;
If v_new_rec_count >0 then
INSERT INTO SOURCE_TEMP SELECT * FROM SOURCE; --insert query 1
Commit;--permanently save the records in table and it wont be rolledback after - -- any subsequent failure.
v_new_rec_count :=0;
end if;
select count(*)
into v_new_rec_count
from (
select * FROM TARGET
minus
select * FROM TARGET_TEMP
) ;
If v_new_rec_count >0 then
INSERT INTO TARGET_TEMP SELECT * FROM TARGET; --insert query 2
Commit;--permanently save the records in table and it wont be rolledback after - -- any subsequent failure.
v_new_rec_count :=0;
end if;
select count(*)
into v_new_rec_count
from (
select * FROM NEWID
minus
select * FROM NEWID_TEMP
) ;
If v_new_rec_count >0 then
INSERT INTO NEWID_TEMP SELECT * FROM NEWID; --insert query 2
Commit;--permanently save the records in table and it wont be rolledback after - -- any subsequent failure.
v_new_rec_count :=0;
end if;
EXCEPTION
WHEN NO_DATA_FOUND THEN DBMS_OUTPUT.PUT_LINE('ERROR');
END;
CREATE OR REPLACE PROCEDURE insert_sql
IS
x int;
FLG FLAG.FLAG%type;
BEGIN
dbms_output.enable;
SELECT FLAG INTO FLG FROM FLAG;
if FLG='PASS01' then
DBMS_OUTPUT.PUT_LINE('PASS01');
DELETE FROM SOURCE_TEMP;
DBMS_OUTPUT.PUT_LINE('SOURCE_TEMP-DELETED');
INSERT INTO SOURCE_TEMP SELECT * FROM SOURCE;
DBMS_OUTPUT.PUT_LINE('SOURCE_TEMP-INSERTED');
UPDATE FLAG SET FLAG='PASS02';
DBMS_OUTPUT.PUT_LINE('PASS02-updated');
SELECT FLAG INTO FLG FROM FLAG;
DBMS_OUTPUT.PUT_LINE('PASS02-SELECT');
COMMIT;
end if;
if FLG='PASS02' then
DBMS_OUTPUT.PUT_LINE('PASS02');
DELETE FROM TARGET_TEMP;
DBMS_OUTPUT.PUT_LINE('TARGET_TEMP-DELETED');
INSERT INTO TARGET_TEMP SELECT * FROM TARGET;
DBMS_OUTPUT.PUT_LINE('TARGET_TEMP-INSERTEDD');
UPDATE FLAG SET FLAG='PASS03';
DBMS_OUTPUT.PUT_LINE('PASS03-updated');
SELECT FLAG INTO FLG FROM FLAG;
DBMS_OUTPUT.PUT_LINE('PASS03-FLG');
COMMIT;
end if;
--x :=1/0;
if FLG='PASS03' then
DBMS_OUTPUT.PUT_LINE('PASS03');
DELETE FROM NEWID_TEMP;
DBMS_OUTPUT.PUT_LINE('NEWID_TEMP-DELETED');
INSERT INTO NEWID_TEMP SELECT * FROM NEWID;
DBMS_OUTPUT.PUT_LINE('NEWID_TEMP-INSERTEDD');
UPDATE FLAG SET FLAG='PASS01';
DBMS_OUTPUT.PUT_LINE('PASS01-updated');
SELECT FLAG INTO FLG FROM FLAG;
DBMS_OUTPUT.PUT_LINE('PASS01-FLG');
COMMIT;
end if;
EXCEPTION WHEN NO_DATA_FOUND THEN DBMS_OUTPUT.PUT_LINE('NO_DATA_FOUND!');
WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE('Error Message: !'|| SQLERRM ||' Sql Code: ' || SQLCODE);
END;
CREATE OR REPLACE PROCEDURE insert_sql
is
v_new_rec_count int:=0;
CURSOR cur_src
IS
SELECT * FROM SOURCE ;
TYPE cur_src_typ IS TABLE OF cur_src%ROWTYPE;
cur_src_tbl cur_src_typ;
CURSOR cur_newid
IS
SELECT * FROM newid ;
TYPE cur_newid_typ IS TABLE OF cur_src%ROWTYPE;
cur_newid_tbl cur_newid_typ;
CURSOR cur_target
IS
SELECT * FROM target ;
TYPE cur_target_typ IS TABLE OF cur_src%ROWTYPE;
cur_target_tbl cur_target_typ;
BEGIN
cur_src_tbl :=cur_src_tbl();
cur_newid_tbl :=cur_newid_tbl();
cur_target_tbl :=cur_target_tbl();
OPEN cur_src;
LOOP
FETCH cur_src BULK COLLECT INTO cur_src_tbl LIMIT 500;
EXIT WHEN cur_src_tbl.count =0;
FOR i IN cur_src LOOP
BEGIN
INSERT INTO SOURCE_TEMP VALUES(cur_src(i).sort_code,cur_src(i).flag);
COMMIT;
EXCEPTION
WHEN OTHERS THEN NULL;
END;
CLOSE cur_src;
OPEN cur_target;
LOOP
FETCH cur_target BULK COLLECT INTO cur_target_tbl LIMIT 500;
EXIT WHEN cur_target.count =0;
FOR i IN cur_target_tbl LOOP
BEGIN
INSERT INTO target_temp VALUES(cur_target_tbl(i).sort_code,cur_target_tbl(i).target_sort_code);
COMMIT;
EXCEPTION
WHEN OTHERS THEN NULL;
END;
CLOSE cur_newid;
OPEN cur_newid;
LOOP
FETCH cur_newid BULK COLLECT INTO cur_newid_tbl LIMIT 500;
EXIT WHEN cur_newid_tbl.count =0;
FOR i IN cur_newid_tbl LOOP
BEGIN
INSERT INTO newid_TEMP VALUES(cur_newid_tbl(i).sort_code,cur_newid_tbl(i).flag);
COMMIT;
EXCEPTION
WHEN OTHERS THEN NULL;
END;
CLOSE cur_newid;
END;
Thanks to All ur support
I created the Proc, Finally I got PLSQL-PROCEDURE to execute my concepts.
create TABLE FLAG
(
FLAG VARCHAR2(6)
);
INSERT INTO FLAG VALUES('PASS01');

After insert Trigger

I'm trying to do a trigger which insert some into column after insert statement. For example I have table with column which looks:
Column1 Column2 Column3
And I'm inserting data into Column 1, Insert into Table(Column1) values ('256234','234234').
Now I would like automatically insert into COlumn2 TImestamp and into Column3 Value "Y", So output should looks:
Column1 Column2 Column3
256234 2015-10-28 08:48 Y
234234 2015-10-28 08:48 Y
Guys, could you help me with that? I tried to use cursor
Finally I got something like that:
create or replace trigger name
after insert on table
declare
c1 sys_refcursor;
idx varchar2(200);
begin
open c1 for select Column1 from table ;
loop
fetch c1 into idx;
exit when c1%NOTFOUND;
update table a1 set a1.Column2 = (select to_char(sysdate,'YYYYMMDDHHMISS') from dual) where Column1=idx;
update table a1 set a1.Column3 = (select 'Y' from dual) where Column1=idx;
end loop;
close c1;
end;
It works fine, but I'm wondering if there is some other better solution than that?
No need for a cursor or even an update:
create or replace trigger name
before insert on table_x
begin
:new.column2 := sysdate;
:new.column3 := 'Y';
end;
/
But you need a before trigger for this, because an after trigger cannot modify the newly inserted row.
But why don't you just define a default value for those columns, then you don't need a trigger at all:
create table table_x
(
column_1 integer,
column_2 date default sysdate,
column_3 varchar(1) default 'Y'
);
You can create trigger as similar :
CREATE OR REPLACE TRIGGER "TRG_NAME"
BEFORE INSERT ON "TABLE_NAME"
FOR EACH ROW
DECLARE
BEGIN
:NEW.Column2 := to_char(sysdate,'YYYYMMDDHHMISS');
:NEW.Column3 := 'Y';
END TRG_NAME ;
/
ALTER TRIGGER "TRG_NAME" ENABLE;
/
Hope this PL/SQL will help you..

select forall array in sql statement(PL/SQL)

Type tabArray IS TABLE OF TABLE%ROWTYPE;
tableArray tabArray ;
--fill array
SELECT *
BULK COLLECT INTO tableArray
FROM TABLE
WHERE TABLE.field = ....
--work
FOR pos IN 1..tableArray .count
LOOP
dbms_output.put_line(pos||' '||audArray(pos).field);
end loop;
--doesn't work
SELECT * TABLE2
WHERE TABLE2.field in (SELECT filed FROM FORALL tableArray );
Main question: how can I use my array in sql statement (in) ?
First you have to create a type in SQL then can use as given below
CREATE TYPE FRUIT_TT AS TABLE OF VARCHAR2(100)
SELECT column_value AS val
FROM TABLE(FRUIT_TT('Apple','Banana','Apricot'))
WHERE column_value NOT LIKE 'A%';
Here a type FRUIT_TT is created and using it in SQL query.
Here is an example, you just need to adjust your SQL statement.
CREATE TYPE col_ntt IS TABLE OF NUMBER;
CREATE TABLE num_tab
(
col NUMBER
);
INSERT INTO num_tab VALUES(1);
INSERT INTO num_tab VALUES(2);
INSERT INTO num_tab VALUES(4);
DECLARE
l_col1 col_ntt := col_ntt(1, 2, 3);
l_col2 col_ntt;
BEGIN
SELECT *
BULK COLLECT INTO l_col2
FROM num_tab
WHERE col IN (SELECT column_value FROM TABLE(l_col1));
FOR indx IN 1..l_col2.COUNT LOOP
DBMS_OUTPUT.PUT_LINE(l_col2(indx));
END LOOP;
END;
/*
1
2
*/