I have a table name as Can
Internal_id not null VARCHAR2(10)
RCR not null VARCHAR2(10)
IVC. not null VARCHAR2(10)
Currently there no values for column RCR
The values stored in column Internal_Id are like
SER00001
SER00002 upto SER00093
I need to update RCR correspondingly to internal_id
Like for SER00001 it will be SERSRV00001
SER00002 it will be SERSRV00002
and so on
I can do this like update Can where
RCR = lpad(Internal_id,3)||'SRV'||substr(Internal_id,4,6) where Internal_id = 'SER00001'
How to update in loop instead of writing so many update statements
update MyTable set RCR = substr(Internal_id, 1, 3) || "SRV" || substr(Internal_id, 4);
You can do a select first to make sure it does the right thing:
select substr(Internal_id, 1, 3) || "SRV" || substr(Internal_id, 4) from MyTable;
Ofcourse the right way to solve your query is using a SQL statement which #Kusalananda mentioned. But incase you specifically wanted to do it in loop(Oracle PL/SQL) then you can use this way as well:
begin
for i in (select * from can)
loop
update can
set RCR = substr(i.Internal_id, 1, 3) || "SRV" || substr(i.Internal_id, 4)
where Internal_id = i.Internal_id;
commit;
end loop;
end;
Related
I have a table which has a column on which I have set a trigger to update the timestamp when there is an update on the row
CREATE TABLE mytable (
id NUMBER NOT NULL,
sid VARCHAR(10) NOT NULL,
stext VARCHAR(10),
tid VARCHAR(10),
ttext VARCHAR(10),
last_updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT unique PRIMARY KEY (id) ENABLE
);
CREATE OR REPLACE trigger last_updated_trigger
BEFORE UPDATE ON mytable
FOR EACH ROW
BEGIN
select systimestamp into :new.last_updated from dual;
END;
/
However, when certain SQLs are executed on the table, I do NOT want the 'last_updated' column to be updated. For instance, when the below SQL updates this table, I do NOT want the trigger to kick in. I need the column to retain the last_updated value so that my other queries do not get messed up. However, when other SQLs do updates on the data, I want the column to be updated.
Any ideas on how this could be done?
MERGE INTO mytable
USING dual
ON (id = ?)
WHEN MATCHED THEN
UPDATE SET
stext = case when sid = ? then ? else stext end,
ttext = case when tid = ? then ? else ttext end
You can easily keep a supplied value and only insert the current time if it is not supplied:
CREATE OR REPLACE trigger last_updated_trigger
BEFORE UPDATE ON mytable
FOR EACH ROW
BEGIN
:new.last_updated := coalesce(:new.last_updated, systimestamp);
END;
If you do not want to fire trigger when you update STEXT or TTEXT columns please try this:
CREATE OR REPLACE trigger last_updated_trigger
BEFORE UPDATE ON mytable
FOR EACH ROW
BEGIN
if (not updating('stext') and not updating('ttext')) then
:new.last_updated := systimestamp;
end if;
END;
Thanks
You can put that specific SQL Statement into a PROCEDURE in which the module info is updated for the concerned application(always call this statement from this procedure only) such as
CREATE OR REPLACE PROCEDURE Merge_Text AS
BEGIN
DBMS_APPLICATION_INFO.SET_MODULE($$plsql_unit,null);
MERGE INTO mytable
USING dual
ON (id = ?)
WHEN MATCHED THEN
UPDATE SET
stext = case when sid = ? then ? else stext end,
ttext = case when tid = ? then ? else ttext end;
END;
/
and then distinguish this caller module within the trigger such as
CREATE OR REPLACE trigger last_updated_trigger
BEFORE UPDATE ON mytable
FOR EACH ROW
v_module VARCHAR2(80);
v_action VARCHAR2(80);
BEGIN
DBMS_APPLICATION_INFO.READ_MODULE(v_module, v_action);
IF v_module != 'MERGE_TEXT' THEN
:new.last_updated := systimestamp;
END IF;
END;
/
I need to update exactly same columns of two tables How do update both through single query, currently I am doing like below;
Update Table1 set col1=val1, col2=val2, col3=val3 where Id in=
(select tt.cId from anotherTable at inner join thirdTable tt on at.id = tt.id)
Update Table2 set col1=val1, col2=val2, col3=val3 where Id in=
(select tt.cId from anotherTable at inner join thirdTable tt on at.id = tt.id)
only change is Table name is different.
P.S. Above is the sample query, original query has several lines of code. I have to minimize the text due to column size, I cannot change the existing size of column
How do I perform this at once or in single query in oracle, both tables are exactly same and also update values are same.
Is there anything like this;
update Table1 t1, Table2 t2 set t1.col1 = val1, t2.col1 = val1, t1.col2 = val2, t2.col2 = val2...
I don't think it is possible in Oracle to update two different target tables in a single statement. But, you can do both updates within a single logical transaction:
START TRANSACTION;
UPDATE 1...
UPDATE 2...
COMMIT;
We cannot update two table in simultaneously so in this case, we can use PL SQL
varchar2 data type to hold the value of update as in pl sql varchar is limit is 32,767 bytes.Hold updated value in a variable and use that varibale to update tables.
A sample code.
desc temp;
Name Null? Type
----------- ----- --------------
ID NUMBER
MDATE DATE
ITEM CHAR(3)
DESCRIPTION VARCHAR2(4000)
set SERVEROUTPUT ON
DECLARE
v_text_update VARCHAR2(32767);
v_query1 VARCHAR2(32767);
v_query2 VARCHAR2(32767);
v_query3 VARCHAR2(32767);
BEGIN
v_query1 := 'update temp set description=' || chr(39);
v_text_update := 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
;
v_query2 := chr(39)
|| ' where id=11';
v_query3 := v_query1
|| v_text_update
|| v_query2;
dbms_output.put_line(v_query3);
EXECUTE IMMEDIATE v_query3; -- OR
EXECUTE IMMEDIATE v_query1
|| v_text_update
|| v_query2; ----instead of storing value in v_query3 you can use
concatenation directly.
END;
/
I hope it helps and let me know if I miss something.
The objective of this automation is to run a couple of select count(*) queries in each row and update/store the result into the rows with respect to the queries. After storing the result into each row, it should proceed on to the next row and until the end of the table. It also should take into consideration if there is no select queries in either of the rows.
For example, there are a total of 4 columns:
a) stored query ( ie. select count(cust) from customers_savings where saving>=‘’;)
b) stored query of another table (ie. select count(cust) from customers_spendings where spending>=‘’;)
c) stores the returned output from a,
d) stores the returned output from b
Would greatly appreciate if there is a template or guideline that I can follow closely with.
Currently using oracle plsql v17.4.
Thanks
Create Table
You could have provided this one ;)
CREATE TABLE TABLETEST
(
QUERY1 VARCHAR2(2000 CHAR),
RESULT1 NUMBER,
QUERY2 VARCHAR2(2000 CHAR),
RESULT2 NUMBER
);
Sample-Data
You should have provided these ;)
INSERT INTO TABLETEST VALUES('SELECT 1 FROM DUAL', 0, 'SELECT 2 FROM DUAL', 0);
INSERT INTO TABLETEST VALUES('SELECT 3 FROM DUAL', 0, 'SELECT 4 FROM DUAL', 0);
Run the queries
declare
tmpResult1 NUMBER;
tmpResult2 NUMBER;
begin
FOR i IN (SELECT query1, query2 FROM TABLETEST) -- loop through every row
LOOP
dbms_output.put_line('query1: "' || i.query1 || '"'); -- let's have a look, what we got back from our select
dbms_output.put_line('query2: "' || i.query2 || '"');
EXECUTE IMMEDIATE i.query1 INTO tmpResult1; -- executor out select-statement
EXECUTE IMMEDIATE i.query2 INTO tmpResult2;
dbms_output.put_line('tmpResult1: ' || tmpResult1); -- let's have a look at our results
dbms_output.put_line('tmpResult2: ' || tmpResult2);
UPDATE TABLETEST SET RESULT1 = tmpResult1, RESULT2 = tmpResult2 WHERE QUERY1 = i.query1 AND QUERY2 = i.query2; -- Store the results into the table.
END LOOP;
end;
Review Result
SELECT * FROM TABLETEST;
Today, I came across a funny piece of code that I think should not compile. It uses an SELECT ... INTO clause within a FOR r IN ... LOOP. Here's a script that compiles on Oracle 11i. The script is a shortened version of actual PL/SQL code compiled in a package, runing in production.
create table tq84_foo (
i number,
t varchar2(10)
);
insert into tq84_foo values (1, 'abc');
insert into tq84_foo values (2, 'def');
declare
rec tq84_foo%rowtype;
begin
for r in (
select i, t
into rec.i, rec.t -- Hmm???
from tq84_foo
)
loop
dbms_output.put_line('rec: i= ' || rec.i || ', t=' || rec.t);
end loop;
end;
/
drop table tq84_foo purge;
The output, when run, is:
rec: i= , t=
rec: i= , t=
I believe 1) I can safely remove the INTO part of the select statement and 2) that this construct should either be invalid or exhibits at least undefined behaviour.
Are my two assumptions right?
Your assumptions are partly right:
1) Yes, you can safely remove the INTO part of the SELECT statement. But you should change the line in the loop to this format:
dbms_output.put_line('rec: i= ' || r.i || ', t=' || r.t);
That way it will get the data out of the r variable
2) The problem with this code is that the syntax of the SELECT ... INTO should fail if the query return more than one row. If it does not fail so it might be a bug and will have unexpected behaviour.
Image I have the following queries in a package:
SELECT col1 FROM table WHERE id=5;
SELECT otherCol FROM otherTable WHERE id=78;
I want to return one record with two columns containing the values 'col1' and 'otherCol'.
In my case, I'd have lots of subqueries and DECODE statements so for readability I want to split it up into different queries something ala:
var result = {}; -- Unfortunately PL/SQL doesn't cope very well with JavaScript.
SELECT col1 INTO someVar FROM table WHERE id=5;
IF someVar = 1 THEN
result.X = SomeQuery();
ELSE
result.X = SomeEntirelyDifferentQuery();
END IF;
SELECT col INTO result.Z FROM tab1;
SELECT coz INTO result.Q FROM tab2;
IF result.Z IS NULL THEN
result.B = Query1();
ELSE
result.B = Query2();
END IF;
... and so on.
RETURN result;
So basically I want to create an "empty record" and then based on some conditions assign different values to columns in that record
This could be solved with DECODE but the resulting query is both not very readable nor very performant.
You have to define an object type the function can return.
CREATE OR REPLACE TYPE fancy_function_result_row as object
(
X number,
Y number,
Q date,
Z varchar2(30)
);
create or replace function fancy_function(...)
return fancy_function_result_row
as
my_record fancy_function_result_row := fancy_function_result_row();
begin
my_record.X := 1;
etc...
end;
If you want to insert the record into a table, it might be a lot easier simply defining a rowtype of that table.
declare
row_my_table my_table%rowtype;
begin
row_my_table.X := etc..
insert into my_table values row_my_table;
end;
--To concat the values 'col1' and 'otherCol':
with r1 as (select col1 from table where id=5),
r2 as (select otherCol from otherTable WHERE id=78),
select r1.col1 || ' concat with ' || r2.othercol from r1, r2
--To do this condition using DECODE:
SELECT DECODE (col1,
1,
(SELECT 1 FROM query1),
(SELECT 1 FROM DifferentQuery)
)
FROM TABLE