In Oracle SQL 11g I am trying to fill a table with procedure. For some columns I need to take data randomly from predefined set of strings. How do I define such set and take data from it by random order?
You could use a cte and dbms_random.value. Something like:
with strings as (
select 'string1' as s from dual union all
select 'string2' as s from dual union all
select 'string3' as s from dual union all
select 'string4' as s from dual
)
select <col1>,
(select s
from (select s from strings order by dbms_random.value) s
where rownum = 1
) as RandomString
from dual;
Can you give this a try,it is working.
1.Insert the list of strings in a table (strings).
2.Create a function(RANDOM) to generate random number.
3.Create a procedure(PROC_STRING) to pick a string name from (STRINGS) table using the random number generated from function(RANDOM) and then insert into (NEW_TABLE)
PROGRAM:
--Table with list of string names
Create table strings (string_id number,string_name varchar2(2000) );
--Table to store new string names in random order
Create table new_table (string_id number,string_name varchar2(2000) );
--Function to generate random numbers
create or replace function random(p_number in number)
return number
is
a number;
begin
select dbms_random.value(1,10) into a
from dual;
a := floor(a);
return a;
end;
/
delete from strings;
delete from new_table;
insert into strings values(1,'abc');
insert into strings values(2,'def');
insert into strings values(3,'ghi');
insert into strings values(4,'abc 1');
insert into strings values(5,'def 1');
insert into strings values(6,'ghi 1');
insert into strings values(7,'abc 2');
insert into strings values(8,'def 2');
insert into strings values(9,'ghi 2');
insert into strings values(10,'xyz 3');
--Procedure to pick string names randomly from strings table and insert into new_table
create or replace procedure proc_string(p_no in number)
as
s_id number;
s_name varchar2(2000);
begin
select random(1) into s_id from dual;
select string_name into s_name from strings where string_id = s_id;
insert into New_table values(s_id,s_name);
dbms_output.put_line('insert successfully completed');
commit;
Exception when others
then dbms_output.put_line('ERROR:' || SQLCODE || ' ' || SQLERRM);
end;
/
commit;
EXECUTION:
--After executing the procedure for 3 times
SQL> exec proc_string(1);
insert successfully completed
PL/SQL procedure successfully completed.
-- Random string names got inserted into newtable
SQL> select * from new_table;
STRING_ID STRING_NAME
5 def 1
3 ghi
1 abc
Let me know if you questions.
Related
Hi because of technical limitation of a Framework I need another way to do a smiliar query without using single quotes
--> current
Select Json_Value(json, '$.bankReference') From R_O where json like '%12345%';
--> Need a Valid query without single quotes which is doing exactly the same thing, maybe a function or something.
Select Json_Value(json, '$.bankReference') From R_O where json like %12345%;
A similar alternative, but a little bit more dynamic
Demo
SQL> create table t1 ( c1 varchar2(10) ) ;
Table created.
SQL> insert into t1 values ( 'A12345B' );
1 row created.
SQL> insert into t1 values ( 'A12345C' );
1 row created.
SQL> insert into t1 values ( 'A12345D' );
1 row created.
SQL> insert into t1 values ( 'A12399B' );
1 row created.
SQL> insert into t1 values ( 'A13299B' );
1 row created.
SQL> insert into t1 values ( 'A21399B' );
1 row created.
SQL> commit ;
Commit complete.
SQL> select * from t1 ;
C1
----------
A12345B
A12345C
A12345D
A12399B
A13299B
A21399B
6 rows selected.
Now let's create a function that admits two parameters:
The column we want to check
The value we want to apply the % ( I am guessing that is always a number ). If the value contains any string, it won't work.
Function
SQL> create or replace function p_chk_json(p_text varchar2, p_val number)
return integer is
begin
if p_text like '%'||p_val||'%' then
return 1;
else
return 0;
end if;
end;
/
Function created.
Then test it for 12345 or 99
SQL> select * from t1 where p_chk_json(c1 , 12345) = 1;
C1
----------
A12345B
A12345C
A12345D
SQL> select * from t1 where p_chk_json(c1 , 99 ) = 1 ;
C1
----------
A12399B
A13299B
A21399B
In Oracle you can write a function something like that:
create or replace function test1(p_text varchar2)
return integer is
begin
if p_text like '%12345%' then
return 1;
else
return 0;
end if;
end test1;
Your modified SQL statement will be:
Select Json_Value(json, '$.bankReference') From R_O where test1(json) = 1;
I have a table having one of the columns that stores SQL query.
create table test1
(
name varchar(20),
stmt varchar(500)
);
insert into test1 (name, stmt)
values ('first', 'select id from data where id = 1;')
Data table is like:
create table data
(
id number,
subject varchar(500)
);
insert into data (id, subject) values (1, 'test subject1');
insert into data (id, subject) values (2, 'test subject2');
insert into data (id, subject) values (3, 'test subject2');
Now every time on insert in test1, I need to execute the query that gets inserted in stmt column of test1 and insert queried data to result table:
create table result
(
id number,
subject varchar(500)
);
For that I am writing a trigger that gets executed on every insert in test1 like as follows:
create or replace TRIGGER "TEST_AFTER_INSERT"
BEFORE INSERT or UPDATE ON test1
FOR EACH ROW
DECLARE
sql_stmt VARCHAR2(500);
BEGIN
select stmt into sql_stmt from data where name = :NEW.name;
insert into result(id, subject)
select id,subject from data where id in ('stmt');
END;
Could you please let me know how to achieve this, above trigger is throwing error that I am not able to understand.
You can use a dynamic query in your trigger as follows:
CREATE OR REPLACE TRIGGER "TEST_AFTER_INSERT" AFTER -- CHANGED IT TO AFTER AS NAME SUGGESTS
INSERT OR UPDATE ON TEST1
FOR EACH ROW -- REMOVED DECLARE SECTION
BEGIN
EXECUTE IMMEDIATE 'INSERT INTO result
SELECT ID, SUBJECT FROM DATA WHERE ID IN ('
|| RTRIM(:NEW.STMT, ';')
|| ')';
-- SINGLE QUERY TO INSERT THE DATA
-- USED RTRIM AS STMT HAS ; AT THE END
END;
Cheers!!
Consider direct insertion :
CREATE OR REPLACE TRIGGER "TEST_AFTER_INSERT"
BEFORE INSERT or UPDATE ON test1
FOR EACH ROW
DECLARE
BEGIN
insert into result(id, subject)
select id, subject from data where name = :NEW.name;
END;
Here's my problem: I'm working inside a pl/sql package where I have a loop that compares the rule with table of users. I need to build a comma separated list of strings (#1) in which I can obtain invalid users (users that doesn't match the rule) and then create a sql query (#2) to exclude them from the rule.
1 Comma separated list:
Z=table that results after comparing the rule with main table of users
Below i am not sure if any of the two commented lines are good
declare user_list varchar2(4000)
IF Z IS NULL THEN
-- build the comma separated list
User_list:= --how to buil a list of strings?
END IF;
2 SQL statement:
--Using the created user_list, now just to exclude it from the main rule
IF USER_LIST IS NULL THEN
'SELECT * FROM RULE WHERE USER NOT IN (:USER_LIST)'
ELSE
RETURN RESULT_FROM_RULE;
END IF;
You can achieve your requirement using dynamic sql. See below how you can do it. I have put the comments inline for understading the code.
create table table1 (id number,
ColumnName varchar2(100))
create table table2 (Id number,
col1 varchar2(100),
col2 varchar2(100),
col3 varchar2(100));
Insert all
into TABLE1 (ID, COLUMNNAME) Values (1, 'col1')
into TABLE1 (ID, COLUMNNAME) Values (2, 'col2')
into TABLE2 (ID, col1, col2, col3) Values (1, 'RRR', 'KKK', 'MMM')
into TABLE2 (ID, col1, col2, col3) Values (2, 'ZZZ', 'PPP', 'QQQ')
into TABLE2 (ID, col1, col2, col3) Values (3, 'LLL', 'NNN', 'DDD')
select * from dual;
Code:
DECLARE
var VARCHAR2 (1000);
v_sql VARCHAR2 (2000);
TYPE x_var IS TABLE OF table2%rowtype ;
z_var x_var;
num number:=0;
BEGIN
FOR rec IN ( SELECT columnname
FROM table1
)
LOOP
num := num +1;
if num = 1 then
var:= rec.columnname;
else
var := var || ' , '|| rec.columnname;
end if;
END LOOP;
---This is how the comma seperated list is generated. This answers your query `**1 Comma separated list:**`
var := RTRIM (LTRIM (var, ','), ',');
--This is how you pass the string to your query . This answers your query `**2 SQL statement:**`
v_sql := 'select * from table2 where segment1 in ('|| var||')';
---This is how you execute your query.
EXECUTE IMMEDIATE v_sql BULK COLLECT INTO z_var;
--displaying the result of the query. If you are using a function you can return (z_var).
FOR i IN 1 .. z_var.COUNT
LOOP
DBMS_OUTPUT.put_line (z_var(i).Id ||','||z_var(i).col1);
END LOOP;
END;
Output:
SQL> /
1,RRR
2,ZZZ
3,LLL
PL/SQL procedure successfully completed.
Note: Please note that the you can use a single query suggested by GurV and simplify your job as well.
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');
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
*/