ROWNUM truncating output recordset - oracle

This query
select id from TABLE where id=1234 or id like '234%'
returns 11 rows, as expected. But when i try this
select rownum as rnum, id from TABLE where id=1234 or id like '234%'
or even this
select * from (
select id from TABLE where id=1234 or id like '234%'
) where rownum < 22
I have only 10 rows (id=1234 is missing in the output recordset). Why is that?
DDL for Table TABLE
CREATE TABLE "TABLE"
( "ID" NUMBER(28,0),
"SPOT_LCK" NUMBER(28,0),
"STATUS" NUMBER(*,0),
"CARRIER_YN" CHAR(1 BYTE),
...
"DRIVER" NUMBER(38,0) DEFAULT 0
);
Constraints for Table TABLE
ALTER TABLE "SCHEMA"."TABLE" ADD CONSTRAINT "PK_TBL" PRIMARY KEY ("ID")
Oracle 12c Release 12.1.0.2.0 - 64bit

Double-check your results, you must have made a mistake. Minimal example:
create table testrn ( id number primary key, c1 number );
insert into testrn values (1234, 1);
insert into testrn values (2341, 2);
insert into testrn values (2342, 3);
insert into testrn values (2343, 4);
insert into testrn values (2344, 5);
insert into testrn values (2345, 6);
insert into testrn values (2346, 7);
insert into testrn values (2347, 8);
insert into testrn values (2348, 9);
insert into testrn values (2349, 10);
insert into testrn values (23410, 11);
commit;
select id, rownum from testrn where id=1234 or id like '234%';
This returns 11 rows as expected. And I assume that you meant 1234 is missing as 123 is not used in the SQL?

There is no solution found as of now: oracle says latest patch required, app vendor says they don't support it. so we're leaving as it is.

Related

Avoid inserting in oracle [duplicate]

I need to be able to run an Oracle query which goes to insert a number of rows, but it also checks to see if a primary key exists and if it does, then it skips that insert. Something like:
INSERT ALL
IF NOT EXISTS( SELECT 1 WHERE fo.primary_key='bar' )
(
INSERT INTO
schema.myFoo fo ( primary_key, value1, value2 )
VALUES
('bar','baz','bat')
),
IF NOT EXISTS( SELECT 1 WHERE fo.primary_key='bar1' )
(
INSERT INTO
schema.myFoo fo ( primary_key, value1, value2 )
VALUES
('bar1','baz1','bat1')
)
SELECT * FROM schema.myFoo;
Is this at all possible with Oracle?
Bonus points if you can tell me how to do this in PostgreSQL or MySQL.
Coming late to the party, but...
With oracle 11.2.0.1 there is a semantic hint that can do this: IGNORE_ROW_ON_DUPKEY_INDEX
Example:
insert /*+ IGNORE_ROW_ON_DUPKEY_INDEX(customer_orders,pk_customer_orders) */
into customer_orders
(order_id, customer, product)
values ( 1234, 9876, 'K598')
;
UPDATE: Although this hint works (if you spell it correctly), there are better approaches which don't require Oracle 11R2:
First approach—direct translation of above semantic hint:
begin
insert into customer_orders
(order_id, customer, product)
values ( 1234, 9876, 'K698')
;
commit;
exception
when DUP_VAL_ON_INDEX
then ROLLBACK;
end;
Second aproach—a lot faster than both above hints when there's a lot of contention:
begin
select count (*)
into l_is_matching_row
from customer_orders
where order_id = 1234
;
if (l_is_matching_row = 0)
then
insert into customer_orders
(order_id, customer, product)
values ( 1234, 9876, 'K698')
;
commit;
end if;
exception
when DUP_VAL_ON_INDEX
then ROLLBACK;
end;
The statement is called MERGE. Look it up, I'm too lazy.
Beware, though, that MERGE is not atomic, which could cause the following effect (thanks, Marius):
SESS1:
create table t1 (pk int primary key, i int);
create table t11 (pk int primary key, i int);
insert into t1 values(1, 1);
insert into t11 values(2, 21);
insert into t11 values(3, 31);
commit;
SESS2: insert into t1 values(2, 2);
SESS1:
MERGE INTO t1 d
USING t11 s ON (d.pk = s.pk)
WHEN NOT MATCHED THEN INSERT (d.pk, d.i) VALUES (s.pk, s.i);
SESS2: commit;
SESS1: ORA-00001
We can combine the DUAL and NOT EXISTS to achieve your requirement:
INSERT INTO schema.myFoo (
primary_key, value1, value2
)
SELECT
'bar', 'baz', 'bat'
FROM DUAL
WHERE NOT EXISTS (
SELECT 1
FROM schema.myFoo
WHERE primary_key = 'bar'
);
This only inserts if the item to be inserted is not already present.
Works the same as:
if not exists (...) insert ...
in T-SQL
insert into destination (DESTINATIONABBREV)
select 'xyz' from dual
left outer join destination d on d.destinationabbrev = 'xyz'
where d.destinationid is null;
may not be pretty, but it's handy :)
If you do NOT want to merge in from an other table, but rather insert new data... I came up with this. Is there perhaps a better way to do this?
MERGE INTO TABLE1 a
USING DUAL
ON (a.C1_pk= 6)
WHEN NOT MATCHED THEN
INSERT(C1_pk, C2,C3,C4)
VALUES (6, 1,0,1);
It that code is on the client then you have many trips to the server so to eliminate that.
Insert all the data into a temportary table say T with the same structure as myFoo
Then
insert myFoo
select *
from t
where t.primary_key not in ( select primary_key from myFoo)
This should work on other databases as well - I have done this on Sybase
It is not the best if very few of the new data is to be inserted as you have copied all the data over the wire.
DECLARE
tmp NUMBER(3,1);
BEGIN
SELECT COUNT(content_id) INTO tmp FROM contents WHERE (condition);
if tmp != 0 then
INSERT INTO contents VALUES (...);
else
INSERT INTO contents VALUES (...);
end if;
END;
I used the code above. It is long, but, simple and worked for me. Similar, to Micheal's code.
If your table is "independent" from others (I mean, it will not trigger a cascade delete or will not set any foreign keys relations to null), a nice trick could be to first DELETE the row and then INSERT it again. It could go like this:
DELETE FROM MyTable WHERE prop1 = 'aaa'; //assuming it will select at most one row!
INSERT INTO MyTable (prop1, ...) VALUES ('aaa', ...);
If your are deleting something which does not exist, nothing will happen.
This is an answer to the comment posted by erikkallen:
You don't need a temp table. If you
only have a few rows, (SELECT 1 FROM
dual UNION SELECT 2 FROM dual) will
do. Why would your example give
ORA-0001? Wouldn't merge take the
update lock on the index key and not
continue until Sess1 has either
committed or rolled back? – erikkallen
Well, try it yourself and tell me whether you get the same error or not:
SESS1:
create table t1 (pk int primary key, i int);
create table t11 (pk int primary key, i int);
insert into t1 values(1, 1);
insert into t11 values(2, 21);
insert into t11 values(3, 31);
commit;
SESS2: insert into t1 values(2, 2);
SESS1:
MERGE INTO t1 d
USING t11 s ON (d.pk = s.pk)
WHEN NOT MATCHED THEN INSERT (d.pk, d.i) VALUES (s.pk, s.i);
SESS2: commit;
SESS1: ORA-00001
INSERT INTO schema.myFoo ( primary_key , value1 , value2 )
SELECT 'bar1' AS primary_key ,'baz1' AS value1 ,'bat1' AS value2 FROM DUAL WHERE (SELECT 1 AS value FROM schema.myFoo WHERE LOWER(primary_key) ='bar1' AND ROWNUM=1) is null;

Convert String List to Number in Oracle DB

I am saving table ids as foreign key into another table using Oracle Apex Shuttle field like(3:4:5). Now I want to use these IDS in sql query using IN Clause. I have replaced : with , using replace function but it shows
no data found
message.
The following query works fine when I use static values.
select * from table where day_id IN(3,4,5)
But when I try to use
select * from table where id IN(Select id from table2)
it shows no data found.
From what i understand you have a list like 1:2:3:4 that you want to use in a IN clause; you can transform the list into separated values like this:
select regexp_substr('1:2:3:4','[^:]+', 1, level) as list from dual
connect by regexp_substr('1:2:3:4', '[^:]+', 1, level) is not null;
This will return:
List
1
2
3
4
Then you can simply add it to your query like this:
SELECT *
FROM TABLE
WHERE day_id IN
(SELECT regexp_substr('1:2:3:4','[^:]+', 1, level) AS list
FROM dual
CONNECT BY regexp_substr('1:2:3:4', '[^:]+', 1, level) IS NOT NULL
);
Can you try below statement. It has working as you expected.
create table table1 (id number, name varchar2(20));
alter table table1 add constraints pri_cons primary key(id);
create table table2 (id number, name varchar2(20));
alter table table2 add constraints ref_cons FOREIGN KEY(id) REFERENCES table1 (id);
begin
insert into table1 values (1,'Bala');
insert into table1 values (2,'Sathish');
insert into table1 values (3,'Subbu');
insert into table2 values (1,'Nalini');
insert into table2 values (2,'Sangeetha');
insert into table2 values (3,'Rubini');
end;
/
select * from table1 where id IN (Select id from table2);

cannot insert data into the 4th table

I used the following script to create 4 test tables: dept1, dept2, dept3, and dept4. The code is exactly the same for each table. All tables are created successfully but the insert into statements only worked for the first three tables. After dropping all tables and purge the recyclebin, I moved Create Table dept4 and the following insert into statements to the top of the code. Then the insert into statement does not work for Dept3. Basically, I can only insert data into the first three tables in the script and not able to insert data into the 4th table on the script.
The error message is the following:
SQL Error: ORA-00604: error occurred at recursive SQL level 1
ORA-30667: cannot drop NOT NULL constraint on a DEFAULT ON NULL column
00604. 00000 - "error occurred at recursive SQL level %s"
This happened after some users created identity columns in Oracle 12.1 database. Some users used:
GENERATED ALWAYS AS IDENTITY
Other users used:
GENERATED BY DEFAULT ON NULL AS IDENTITY
Code used:
CREATE TABLE DEPT1 (
DEPT1NO NUMBER(2) NOT NULL,
DNAME VARCHAR2(14),
LOC VARCHAR2(13),
CONSTRAINT DEPT1_PRIMARY_KEY PRIMARY KEY (DEPT1NO));
INSERT INTO DEPT1 VALUES (10,'ACCOUNTING','NEW YORK');
INSERT INTO DEPT1 VALUES (20,'RESEARCH','DALLAS');
INSERT INTO DEPT1 VALUES (30,'SALES','CHICAGO');
INSERT INTO DEPT1 VALUES (40,'OPERATIONS','BOSTON');
CREATE TABLE DEPT2 (
DEPT2NO NUMBER(2) NOT NULL,
DNAME VARCHAR2(14),
LOC VARCHAR2(13),
CONSTRAINT DEPT2_PRIMARY_KEY PRIMARY KEY (DEPT2NO));
INSERT INTO DEPT2 VALUES (10,'ACCOUNTING','NEW YORK');
INSERT INTO DEPT2 VALUES (20,'RESEARCH','DALLAS');
INSERT INTO DEPT2 VALUES (30,'SALES','CHICAGO');
INSERT INTO DEPT2 VALUES (40,'OPERATIONS','BOSTON');
CREATE TABLE DEPT3 (
DEPT3NO NUMBER(2) NOT NULL,
DNAME VARCHAR2(14),
LOC VARCHAR2(13),
CONSTRAINT DEPT3_PRIMARY_KEY PRIMARY KEY (DEPT3NO));
INSERT INTO DEPT3 VALUES (10,'ACCOUNTING','NEW YORK');
INSERT INTO DEPT3 VALUES (20,'RESEARCH','DALLAS');
INSERT INTO DEPT3 VALUES (30,'SALES','CHICAGO');
INSERT INTO DEPT3 VALUES (40,'OPERATIONS','BOSTON');
CREATE TABLE DEPT4 (
DEPT4NO NUMBER(2) NOT NULL,
DNAME VARCHAR2(14),
LOC VARCHAR2(13),
CONSTRAINT DEPT4_PRIMARY_KEY PRIMARY KEY (DEPT4NO));
INSERT INTO DEPT4 VALUES (10,'ACCOUNTING','NEW YORK');
INSERT INTO DEPT4 VALUES (20,'RESEARCH','DALLAS');
INSERT INTO DEPT4 VALUES (30,'SALES','CHICAGO');
INSERT INTO DEPT4 VALUES (40,'OPERATIONS','BOSTON');

Copy or show the primary key value into another table as foreign key APEX

I have two tables A and B .i want to copy or show the primary key column value from table A in the foreign key column in table B respectively .is there any method kindly help me.
Regards,
You can populate your primary key value while populating table B or by using a trigger when you are populating table A.
CREATE TABLE t1 (id1 NUMBER, dt DATE);
ALTER TABLE t1 ADD (
CONSTRAINT t1_pk
PRIMARY KEY
(id1));
CREATE TABLE t2 (id2 NUMBER, id1 NUMBER, dt2 DATE);
ALTER TABLE t2 ADD (
CONSTRAINT t2_pk
PRIMARY KEY
(id2));
ALTER TABLE t2
ADD CONSTRAINT t2_r01
FOREIGN KEY (id2)
REFERENCES t1 (id1);
First Approach, by this way you could populate second table when you are inserting values.
INSERT INTO t1
VALUES (1, SYSDATE
);
INSERT INTO t2
VALUES (1, 1, SYSDATE
);
With trigger, so when values are inserted into first table second tables values are populated using a trigger. So primary key value of first table is being inserted into foreign key of table 2.
CREATE OR REPLACE TRIGGER my_trigger
AFTER INSERT
ON t1
FOR EACH ROW
BEGIN
INSERT INTO t2
VALUES (1, :new.id1, SYSDATE
);
EXCEPTION
WHEN NO_DATA_FOUND
THEN
DBMS_OUTPUT.put_line (TO_CHAR (SQLERRM (-20299)));
WHEN OTHERS
THEN
DBMS_OUTPUT.put_line (TO_CHAR (SQLERRM (-20298)));
END;

How to update 2 tables using triggers

I have 2 tables,
lv_data,
It has the following fields,
emp_name tot_days
guru 18
leave_data
it has the following fields,
emp_name From_date to_date no_of_days remaining_days
guru 02/05/2012 03/05/2012 2
In second table if the data is inserted, the no_of_days will be automatically calculated (from to_date - From_date)+1
Here I need to write the trigger to update the remaining_days column,
In first table for all emp_name, tot_days is 18 days, so in second table whenever the record is inserted, the remaining_days should be calculated like this
remaining_days := tot_days - no_of_days
And this(calculated) value should be updated in tot_days column in first table(lv_data),
Sample Example:
emp_name tot_days
guru 18
leave_data
emp_name From_date to_date no_of_days remaining_days
guru 02/05/2012 03/05/2012 2 16
Now the first table should be updated like,
emp_name tot_days
guru 16
So I need to update 2 tables. Can someone help me to update these 2 tables through trigger?
Have an before insert trigger on the table which will set the record before inserting it
Few things to note:
Your data model doesn't have a unique identifier for a row
I don't think your "no_of_days" calculation is right.
CREATE OR replace TRIGGER leave_data_before_insert
BEFORE INSERT ON LEAVE_DATA
FOR EACH ROW
DECLARE
CURSOR c_lv_data(
p_emp_id IN lv_data.id%TYPE) IS
SELECT tot_days
FROM lv_data
WHERE id = p_emp_id;
v_tot_days NUMBER;
BEGIN
OPEN c_lv_data(:new.id);
FETCH c_lv_data INTO v_tot_days;
:new.no_of_days := ( :new.from_date - :new.TO_DATE ) + 1;
:new.remaining_days := v_tot_days - :new.no_of_days;
UPDATE lv_data
SET tot_days = :new.remaining_days
WHERE id = :new.id;
CLOSE c_lv_data;
END;
DDL used to test:
CREATE TABLE lv_data
(
id NUMBER,
emp_name VARCHAR2(240),
tot_days NUMBER
);
CREATE TABLE leave_data
(
id NUMBER,
emp_name VARCHAR2(240),
from_date DATE,
to_date DATE,
no_of_days NUMBER,
remaining_days NUMBER
);
DML used to test:
INSERT INTO lv_data
VALUES (1,
'sathya',
18);
INSERT INTO LEAVE_DATA
VALUES ('1',
'sathya',
SYSDATE,
SYSDATE + 2,
NULL,
NULL);

Resources