Difference between execute current query and execute current script in oracle - oracle

I need to complete multiple inserts in Oracle.
insert into table_name (ID, code, date_t)
values (schema_name.SEQ$table_name.NEXTVAL, '232323232323' , to_date('2020-09-01','YYYY-MM-DD'));
insert into table_name (ID, code, date_t)
values (schema_name.SEQ$table_name.NEXTVAL, '242424242424' , to_date('2020-09-01','YYYY-MM-DD'));
I can't complete them when trying to use simple execute because it gives me an error: ora-00933 sql command not properly ended
But when I using execute as script it works fine.
The main problem is that I can't explain that to people how to complete that script in the console.
Maybe there are some other options to complete multiple inserts in Oracle?

Use INSERT ... SELECT:
insert into table_name (ID, code, date_t)
WITH data (code, date_t) AS (
SELECT '232323232323', DATE '2020-09-01' FROM DUAL UNION ALL
SELECT '242424242424', DATE '2020-09-01' FROM DUAL
)
SELECT SEQ$table_name.NEXTVAL, code, date_t FROM data;
You could also use INSERT ALL; however, you have to jump through some hoops to get it to work with a sequence so I would suggest not using this option:
INSERT ALL
WHEN rn = 1 THEN
INTO table_name (id, code, date_t)
VALUES (SEQ$table_name.NEXTVAL, '252525252525', DATE '2020-09-01')
WHEN rn = 2 THEN
INTO table_name (id, code, date_t)
VALUES (SEQ$table_name.CURRVAL, '262626262626', DATE '2020-09-01')
SELECT LEVEL AS rn
FROM DUAL
CONNECT BY LEVEL <= 2;

Related

INSERT … SELECT : missing SELECT keyword

I am experimenting with a recursive CTE to split a string into multiple values. The data is then inserted into another table.
The following works in PostgreSQL:
CREATE TABLE test(data varchar(255));
WITH RECURSIVE
cte(genres) AS (SELECT 'apple,banana,cherry,date'),
split(genre,rest,genres) AS (
SELECT '', genres||',',genres FROM cte
UNION ALL
SELECT
substring(rest,0,position(',' IN rest)),
substring(rest,position(',' IN rest)+1),
genres
FROM split WHERE rest<>''
)
INSERT INTO test(data)
SELECT genre
FROM split;
However, the Oracle version:
CREATE TABLE test(data varchar(255));
WITH
cte(genres) AS (SELECT 'apple,banana,cherry,date' FROM dual),
split(genre,rest,genres) AS (
SELECT '', genres||',',genres FROM cte
UNION ALL
SELECT
substr(rest,1,instr(rest,',')-1),
substr(rest,instr(rest,',')+1),
genres
FROM split WHERE rest IS NOT NULL
)
INSERT INTO test(data)
SELECT genre
FROM split WHERE genre IS NOT NULL;
gives me the error message:
ORA-00928: missing SELECT keyword.
Now I’m pretty sure that I’ve got one, there between the INSERT and the following FROM.
If you comment out the INSERT, the rest of it will give the results. Elsewhere, I know that a simple INSERT … SELECT does work.
Is it something to do with the recursive CTE? How can I get this to work properly using a standard recursive CTE?
Using Oracle 18c in a Docker image. There is a fiddle here: https://dbfiddle.uk/?rdbms=oracle_18&fiddle=d24f3105634933af1b7072bded1dacdf .
An INSERT-SELECT means "INSERT" command first, then the SELECT part, and the WITH is part of the SELECT not the insert.
SQL> create table t ( x int );
Table created.
SQL> with blah as ( select 1 c from dual)
2 insert into t
3 select * from blah;
insert into t
*
ERROR at line 2:
ORA-00928: missing SELECT keyword
SQL> insert into t
2 with blah as ( select 1 c from dual)
3 select * from blah;
1 row created.

Oracle 18c multiple insert errors

I need to complete multiple insert in Oracle table about 100k rows. But when I try do like this:
insert into table_name (ID, code, date_t)
values (schema_name.SEQ$table_name.NEXTVAL, '232323232323' , to_date('2020-09-01','YYYY-MM-DD'));
insert into table_name (ID, code, date_t)
values (schema_name.SEQ$table_name.NEXTVAL, '242424242424' , to_date('2020-09-01','YYYY-MM-DD'));
I'm getting an error :
ora-00933 sql command not properly ended
I tried to make it using insert all:
insert ALL
INTO table_name (ID, code, date_t) values (schema_name.SEQ$table_name.NEXTVAL, '232323232323' , to_date('2020-09-01','YYYY-MM-DD'))
INTO table_name (ID, code, date_t) values (schema_name.SEQ$table_name.NEXTVAL, '242424242424' , to_date('2020-09-01','YYYY-MM-DD'))
SELECT 1 FROM schema_name.table_name;
But I'm getting an error:
ORA-00001: unique constraint (constraint_name) violated
How can I solve that errors or How can I make multiple insert in oracle?
There's nothing wrong with those inserts.
SQL> desc table_name
Name Null? Type
----------------------------------------- -------- ----------------------------
ID NUMBER
CODE VARCHAR2(20)
DATE_T DATE
SQL> INSERT INTO table_name (ID, code, date_t)
2 VALUES (scott.SEQ$table_name.NEXTVAL,
3 '232323232323',
4 TO_DATE ('2020-09-01', 'YYYY-MM-DD'));
1 row created.
SQL> INSERT INTO table_name (ID, code, date_t)
2 VALUES (scott.SEQ$table_name.NEXTVAL,
3 '242424242424',
4 TO_DATE ('2020-09-01', 'YYYY-MM-DD'));
1 row created.
SQL>
Therefore, it must be the way you're running those inserts. Let me guess: if it is TOAD and there's no empty line between each insert, it'll return ORA-00933 so "solution" is to execute them as a script (F5).
Some other GUI might require different action.
So - how exactly are you running those commands?

Query taking long when i use user defined function with order by in oracle select

I have a function, which will get greatest of three dates from the table.
create or replace FUNCTION fn_max_date_val(
pi_user_id IN number)
RETURN DATE
IS
l_modified_dt DATE;
l_mod1_dt DATE;
l_mod2_dt DATE;
ret_user_id DATE;
BEGIN
SELECT MAX(last_modified_dt)
INTO l_modified_dt
FROM table1
WHERE id = pi_user_id;
-- this table contains a million records
SELECT nvl(MAX(last_modified_ts),sysdate-90)
INTO l_mod1_dt
FROM table2
WHERE table2_id=pi_user_id;
-- this table contains clob data, 800 000 records, the table 3 does not have user_id and has to fetched from table 2, as shown below
SELECT nvl(MAX(last_modified_dt),sysdate-90)
INTO l_mod2_dt
FROM table3
WHERE table2_id IN
(SELECT id FROM table2 WHERE table2_id=pi_user_id
);
execute immediate 'select greatest('''||l_modified_dt||''','''||l_mod1_dt||''','''||l_mod2_dt||''') from dual' into ret_user_id;
RETURN ret_user_id;
EXCEPTION
WHEN OTHERS THEN
return SYSDATE;
END;
this function works perfectly fine and executes within a second.
-- random user_id , just to test the functionality
SELECT fn_max_date_val(100) as max_date FROM DUAL
MAX_DATE
--------
27-02-14
For reference purpose i have used the table name as table1,table2 and table3 but my business case is similar to what i stated below.
I need to get the details of the table1 along with the highest modified date among the three tables.
I did something like this.
SELECT a.id,a.name,a.value,fn_max_date_val(id) as max_date
FROM table1 a where status_id ='Active';
The above query execute perfectly fine and got result in millisecods. But the problem came when i tried to use order by.
SELECT a.id,a.name,a.value,a.status_id,last_modified_dt,fn_max_date_val(id) as max_date
FROM table1 where status_id ='Active' a
order by status_id desc,last_modified_dt desc ;
-- It took almost 300 seconds to complete
I tried using index also all the values of the status_id and last_modified, but no luck. Can this be done in a right way?
How about if your query is like this?
select a.*, fn_max_date_val(id) as max_date
from
(SELECT a.id,a.name,a.value,a.status_id,last_modified_dt
FROM table1 where status_id ='Active' a
order by status_id desc,last_modified_dt desc) a;
What if you don't use the function and do something like this:
SELECT a.id,a.name,a.value,a.status_id,last_modified_dt x.max_date
FROM table1 a
(
select max(max_date) as max_date
from (
SELECT MAX(last_modified_dt) as max_date
FROM table1 t1
WHERE t1.id = a.id
union
SELECT nvl(MAX(last_modified_ts),sysdate-90) as max_date
FROM table2 t2
WHERE t2.table2_id=a.id
...
) y
) x
where a.status_id ='Active'
order by status_id desc,last_modified_dt desc;
Syntax might contain errors, but something like that + the third table in the derived table too.

Oracle predicate issue

I am having some unusual issue. Whenever i run this query my database disconnects automatically or this error occurs: ORA-12805: parallel query server died unexpectedly.
BEGIN
EXECUTE IMMEDIATE
'CREATE TABLE ZZZ_CLAIMS_00172414_MEMID PARALLEL NOLOGGING AS
SELECT MEMID, ENRID, MEMFIRSTNAME, MEMLASTNAME,GENDER,DOB
FROM
(
SELECT /*+parallel(a,4)*/
MEMID,
ENRID,
MEMFIRSTNAME,
MEMLASTNAME,
GENDER,
DOB,
LVLID2,
ROW_NUMBER() OVER(
PARTITION BY
MEMFIRSTNAME, MEMLASTNAME,GENDER,DOB ORDER BY EFFDATE DESC,TERMDATE DESC NULLS LAST) RN
FROM vh_eligibilities a
WHERE LVLID2 = ''00172414''
)
WHERE RN =1
'; --248969
EXCEPTION WHEN OTHERS THEN NULL;
END;
But when i remove where condition i.e WHERE LVLID2 = ''00172414'', table is created successfully. I consulted with my DBA , he suggested to alter session before creating table.
BEGIN
EXECUTE IMMEDIATE 'ALTER SESSION SET "_pred_move_around" = FALSE';
EXCEPTION WHEN OTHERS THEN NULL;
END;
After altering session table is created successfully. I was using this for past two weeks then today i had to create similar table . But today table was created without using alter session query.
Then i realised i was using same query with little difference:
BEGIN
EXECUTE IMMEDIATE
'CREATE TABLE ZZZ_CLAIMS_00172414_MEMID PARALLEL NOLOGGING AS
SELECT MEMID, ENRID, MEMFIRSTNAME, MEMLASTNAME,GENDER,DOB,**LVLID2**----- The difference ------
FROM
(
SELECT /*+parallel(a,4)*/
MEMID,
ENRID,
MEMFIRSTNAME,
MEMLASTNAME,
GENDER,
DOB,
LVLID2,
ROW_NUMBER() OVER(
PARTITION BY
MEMFIRSTNAME, MEMLASTNAME,GENDER,DOB ORDER BY EFFDATE DESC,TERMDATE DESC NULLS LAST) RN
FROM vh_eligibilities a
WHERE LVLID2 = ''00172414''
)
WHERE RN =1
'; --248969
EXCEPTION WHEN OTHERS THEN NULL;
END;
Can anyone tell me why i was getting this error, and after altering session table was successfully created.
And without altering session , just adding lvlid2 in select statement while creating table , table was created.
Any help would be highly appreciated.

Oracle Equivalent to MySQL INSERT IGNORE?

I need to update a query so that it checks that a duplicate entry does not exist before insertion. In MySQL I can just use INSERT IGNORE so that if a duplicate record is found it just skips the insert, but I can't seem to find an equivalent option for Oracle. Any suggestions?
If you're on 11g you can use the hint IGNORE_ROW_ON_DUPKEY_INDEX:
SQL> create table my_table(a number, constraint my_table_pk primary key (a));
Table created.
SQL> insert /*+ ignore_row_on_dupkey_index(my_table, my_table_pk) */
2 into my_table
3 select 1 from dual
4 union all
5 select 1 from dual;
1 row created.
Check out the MERGE statement. This should do what you want - it's the WHEN NOT MATCHED clause that will do this.
Do to Oracle's lack of support for a true VALUES() clause the syntax for a single record with fixed values is pretty clumsy though:
MERGE INTO your_table yt
USING (
SELECT 42 as the_pk_value,
'some_value' as some_column
FROM dual
) t on (yt.pk = t.the_pke_value)
WHEN NOT MATCHED THEN
INSERT (pk, the_column)
VALUES (t.the_pk_value, t.some_column);
A different approach (if you are e.g. doing bulk loading from a different table) is to use the "Error logging" facility of Oracle. The statement would look like this:
INSERT INTO your_table (col1, col2, col3)
SELECT c1, c2, c3
FROM staging_table
LOG ERRORS INTO errlog ('some comment') REJECT LIMIT UNLIMITED;
Afterwards all rows that would have thrown an error are available in the table errlog. You need to create that errlog table (or whatever name you choose) manually before running the insert using DBMS_ERRLOG.CREATE_ERROR_LOG.
See the manual for details
I don't think there is but to save time you can attempt the insert and ignore the inevitable error:
begin
insert into table_a( col1, col2, col3 )
values ( 1, 2, 3 );
exception when dup_val_on_index then
null;
end;
/
This will only ignore exceptions raised specifically by duplicate primary key or unique key constraints; everything else will be raised as normal.
If you don't want to do this then you have to select from the table first, which isn't really that efficient.
Another variant
Insert into my_table (student_id, group_id)
select distinct p.studentid, g.groupid
from person p, group g
where NOT EXISTS (select 1
from my_table a
where a.student_id = p.studentid
and a.group_id = g.groupid)
or you could do
Insert into my_table (student_id, group_id)
select distinct p.studentid, g.groupid
from person p, group g
MINUS
select student_id, group_id
from my_table
A simple solution
insert into t1
select from t2
where not exists
(select 1 from t1 where t1.id= t2.id)
This one isn't mine, but came in really handy when using sqlloader:
create a view that points to your table:
CREATE OR REPLACE VIEW test_view
AS SELECT * FROM test_tab
create the trigger:
CREATE OR REPLACE TRIGGER test_trig
INSTEAD OF INSERT ON test_view
FOR EACH ROW
BEGIN
INSERT INTO test_tab VALUES
(:NEW.id, :NEW.name);
EXCEPTION
WHEN DUP_VAL_ON_INDEX THEN NULL;
END test_trig;
and in the ctl file, insert into the view instead:
OPTIONS(ERRORS=0)
LOAD DATA
INFILE 'file_with_duplicates.csv'
INTO TABLE test_view
FIELDS TERMINATED BY ','
(id, field1)
How about simply adding an index with whatever fields you need to check for dupes on and say it must be unique? Saves a read check.
yet another "where not exists"-variant using dual...
insert into t1(id, unique_name)
select t1_seq.nextval, 'Franz-Xaver' from dual
where not exists (select 1 from t1 where unique_name = 'Franz-Xaver');

Resources