Is commit necessary after DML operation on table using simple sql query? - sql

Is it necessary to run the COMMIT command after a DML operation in SQL Developer? For example, I performed the following UPDATE query:
UPDATE TAB1
SET TBX_TYP='ZX'
WHERE TBX_TYP IN(SELECT TBX_TYP
FROM(
SELECT DISTINCT TBX_TYP
FROM TAB1
ORDER BY 1 )
WHERE ROWNUM=1);
Then when I tried filtering columns, I found that nothing was updated.

The COMMIT instruction is necessary if you want you changes will be available for other users/connections, for example:
Session1:
SQL> conn hr/hr
Connected.
SQL> truncate table ttt;
Table truncated.
SQL> desc ttt;
Name Null? Type
----------------------------------------- -------- ----------------------------
COL1 NOT NULL VARCHAR2(20 CHAR)
SQL> insert into ttt values('one');
1 row created.
SQL> select col1 from ttt;
COL1
--------------------
one
So new data is available in current session.
Session2:
SQL> conn hr/hr
Connected.
SQL> select col1 from ttt;
no rows selected
But another session can't see this data. So let's commit it:
Session1:
SQL> commit;
Commit complete.
Session2:
SQL> /
COL1
--------------------
one
Now this value is available for both sessions.
But commit also is necessary to store data in you data files.
For example let's add a new row to the ttt table but don't commit it:
Session1:
SQL> insert into ttt values('two');
1 row created.
SQL> select col1 from ttt;
COL1
--------------------
one
two
Then let's shutdown the database abnormally and the start it again
Session2:
SQL> conn / as sysdba
Connected.
SQL> shutdown abort
ORACLE instance shut down.
SQL> startup
ORACLE instance started.
Total System Global Area 1068937216 bytes
Fixed Size 2260048 bytes
Variable Size 616563632 bytes
Database Buffers 444596224 bytes
Redo Buffers 5517312 bytes
Database mounted.
Database opened.
SQL>
Then reconnect Session1 and look at the ttt table:
SQL> conn hr/hr
Connected.
SQL> select col1 from ttt;
COL1
--------------------
one
As you can see, the database doesn't store uncommited data in its data files.

Add Commit after every DML(update, delete, insert) command.

Related

Create Auto Sequence text and number in oracle 11g

How I do create column ID with value JASG1?
I am only find example like this :
select 'JASG'||to_char(mtj_id_seq.nextval) from talend_job
Although what you wrote probably works (if there's a sequence named MTJ_ID_SEQ, you have a privilege to select from it; the same goes for the TALEND_JOB table), I'd say that it isn't what you should use.
Here's why: I'll create a table and a sequence. Table will be pre-populated with some IDs (just to put something in there).
SQL> create sequence mtj_id_seq;
Sequence created.
SQL> create table talend_job as
2 select rownum id from dept;
Table created.
SQL> select * from talend_job;
ID
----------
1
2
3
4
OK; 4 rows so far. Now, run your SELECT:
SQL> select 'JASG'||to_char(mtj_id_seq.nextval) from talend_job;
'JASG'||TO_CHAR(MTJ_ID_SEQ.NEXTVAL)
--------------------------------------------
JASG1
JASG2
JASG3
JASG4
SQL> select 'JASG'||to_char(mtj_id_seq.nextval) from talend_job;
'JASG'||TO_CHAR(MTJ_ID_SEQ.NEXTVAL)
--------------------------------------------
JASG5
JASG6
JASG7
JASG8
SQL>
See? You didn't get only 1 JASGx value, but as many as number of rows in the TALEND_JOB table. If there was a million rows, you'd get a million JASGx rows as well.
Therefore, maybe you meant to use DUAL table instead? E.g.
SQL> select 'JASG'||to_char(mtj_id_seq.nextval) from dual;
'JASG'||TO_CHAR(MTJ_ID_SEQ.NEXTVAL)
--------------------------------------------
JASG9
SQL> select 'JASG'||to_char(mtj_id_seq.nextval) from dual;
'JASG'||TO_CHAR(MTJ_ID_SEQ.NEXTVAL)
--------------------------------------------
JASG10
SQL>
See? Only one value.
Also, notice that sequences will provide unique values, but you can't rely on them being gapless.
As you mentioned "how to create column ID" - one option is to use a trigger. Here's an example:
SQL> create table talend_job (id varchar2(20), name varchar2(20)
Table created.
SQL> create or replace trigger trg_bi_tj
2 before insert on talend_job
3 for each row
4 begin
5 :new.id := 'JASG' || mtj_id_seq.nextval;
6 end;
7 /
Trigger created.
Let's insert some names; IDs should be auto-populated by the trigger:
SQL> insert into talend_job (name) values ('littlefoot');
1 row created.
SQL> insert into talend_job (name) values ('Ishak');
1 row created.
SQL> select * From talend_job;
ID NAME
-------------------- --------------------
JASG11 littlefoot
JASG12 Ishak
SQL>
OK then; now you have some more info - read and think about it.
By the way, what is the "compiler-errors" tag used for? Did you write any code and it failed? Perhaps you'd want to share it with us.

Does SELECT start transaction in PL/SQL

I was told that following code won't help me to check duplicity, because result might be different before SELECT and UPDATE statement.
PROCEDURE AddNew(Pname VARCHAR2, Pcountry VARCHAR2)
AS
already_exists BOOLEAN;
BEGIN
SELECT COUNT(*)>0 INTO already_exists FROM Publishers WHERE name=Pname;
IF already_exists THEN
RAISE_APPLICATION_ERROR(-20014,'Publisher already exists!');
END IF;
INSERT INTO Publishers(id,name,country)
VALUES (NewPublisherId(),Pname,Pcountry);
END;
This post claims that SELECT starts a transaction:
Why do I get an open transaction when just selecting from a database View?
This part of documentation suggests otherwise:
A transaction implicitly begins with any operation that obtains a TX
lock:
When a statement that modifies data is issued
When a SELECT ... FOR UPDATE statement is issued
When a transaction is explicitly started with a SET TRANSACTION statement or the DBMS_TRANSACTION package
So? Does SELECT start a transaction or not?
The latter is true: https://docs.oracle.com/cloud/latest/db112/SQLRF/statements_10005.htm#SQLRF01705
A transaction implicitly begins with any operation that obtains a TX
lock:
When a statement that modifies data is issued
When a SELECT ... FOR UPDATE statement is issued
When a transaction is explicitly started with a SET TRANSACTION statement or the DBMS_TRANSACTION package
But it really does not matter, from the point of view of the main problem - to see if the record already exists in the database. Even if the transaction is explicitely startet using SET TRANSACTION ..., your code simply does not detect duplicate transactions !
Just do a simple test manually simulating the procedure in two simultaneous sessions and you will see:
CREATE TABLE Publishers(
id int,
name varchar2(100)
);
Let say that in session #1 the procedure begins at 8:00:00.0000:
SQL> Set transaction name 'session 1';
Transaction set.
SQL> select count(*) FROM Publishers where name = 'John';
COUNT(*)
----------
0
SQL> INSERT INTO Publishers(id,name) VALUES(1,'John');
1 row created.
Let say that in session #2 the same procedure begins at 8:00:00.0020, just after the insert was made in session 1, but still before the session#1 commits:
SQL> Set transaction name 'session 2';
Transaction set.
SQL> select count(*) FROM Publishers where name = 'John';
COUNT(*)
----------
0
The transaction #2 does not see uncommited changes done by the session 1, so the session 2 assumess that there is no record John, so it also inserts it to the table:
SQL> INSERT INTO Publishers(id,name) VALUES(1,'John');
1 row created.
Now the session 1 commits:
SQL> Commit;
Commit complete.
and a few milliseconds later the session2 commits too:
SQL> Commit;
Commit complete.
And the final result is - a duplicated record even though the transaction has been explicitelly started:
select * from publishers;
ID NAME
---------- ----------------------------------------------------------------------------------------------------
1 John
1 John
========== EDIT =================
You can avoid the duplicity by executing statement SET TRANSACTION
ISOLATION LEVEL SERIALIZABLE in the beginning. – #Draex_
Many think that ISOLATION LEVEL SERIALIZABLE will solve the problem magically. Unfortunately, it will not help.
Let's see how it works on a simple example:
Session #1
SQL> SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
Transaction set.
SQL> select count(*) FROM Publishers where name = 'John';
COUNT(*)
----------
0
SQL> INSERT INTO Publishers(id,name) VALUES(1,'John');
1 row created.
Session #2
SQL> SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
Transaction set.
SQL> select count(*) FROM Publishers where name = 'John';
COUNT(*)
----------
0
SQL> INSERT INTO Publishers(id,name) VALUES(1,'John');
1 row created.
Session #1 again:
SQL> commit;
Commit complete.
SQL> select * from publishers;
ID NAME
---------- --------
1 John
and back to session #2
SQL> commit;
Commit complete.
SQL> select * from publishers;
ID NAME
---------- --------
1 John
1 John
As you can see, the magic of ISOLATION LEVEL SERIALIZABLE did not work.

Setting NLS_SORT variable for a single select only

Good day,
my customer uses an application that was initially designed for MSSQL, which is probably doing case-insensitive searches by default. But the customer uses Oracle and hence, needs some extra tweaking.
So the question is: How can I tell Oracle to make a given SELECT LIKE-Statement search case-insensitive with the following limitations?
ALTER SESSION cannot be used individually (by trigger: maybe)
Other queries from the same session must not be affected
The SELECT-statement cannot be altered
I know about the possibility to set NLS_SORT on system level, but this will basically kill the performance, as all indexes are disabled.
You can use DBMS_ADVANCED_REWRITE to rewrite the SQL into a case-insensitive version.
Subtly changing queries like this can be confusing and can make troubleshooting and tuning difficult. The package also has some limitations that may make it impractical, such as not supporting bind variables.
1. Sample Schema
SQL> drop table test1;
Table dropped.
SQL> create table test1(a varchar2(100));
Table created.
SQL> insert into test1 values ('case INSENSITIVE');
1 row created.
SQL> commit;
Commit complete.
2. The query is initially case-sensitive and matches 0 rows
SQL> select count(*) total from test1 where a like '%case insensitive%';
TOTAL
----------
0
3. Create rewrite equivalence - add a LOWER function
SQL> begin
2 sys.dbms_advanced_rewrite.declare_rewrite_equivalence(
3 name => 'case_insensitive_1',
4 source_stmt => q'[select count(*) total from test1 where a like '%case insensitive%']',
5 destination_stmt => q'[select count(*) total from test1 where lower(a) like '%case insensitive%']',
6 validate => false
7 );
8 end;
9 /
PL/SQL procedure successfully completed.
4. Now the same query is case-insensitive and matches 1 row
SQL> alter session set query_rewrite_integrity = trusted;
Session altered.
SQL> select count(*) total from test1 where a like '%case insensitive%';
TOTAL
----------
1

IF Statement inside Trigger Clause

I want to use an if statement inside trigger but the value if comparison will come from an other select statement.
I have done the following:
create or replace
Trigger MYTRIGGER
After Insert On Table1
Referencing Old As "OLD" New As "NEW"
For Each Row
Begin
Declare Counter Int;
Select Count(*) From Table2 Where Table2."Email" = :New.U_MAIL Into Counter;
IF Counter < 1 THEN
//INSERT Statement here...
END IF;
End;
My logic is simple, if same email user exists, insert will not work.
Above code did not work. How can we do this?
A few syntax errors. Would be closer to something like this:
create or replace
Trigger MYTRIGGER
After Insert On Table1
Referencing Old As "OLD" New As "NEW"
For Each Row
DECLARE
v_count NUMBER;
BEGIN
SELECT COUNT(*)
INTO v_count
FROM Table2
WHERE Email = :New.U_MAIL
;
IF v_count > 0
THEN
RAISE_APPLICATION_ERROR(-20000, 'Not inserted...');
END IF;
END;
Your approach is wrong. Referential integrity should not be made using triggers, it just cannot work as required. See example:
Connected to Oracle Database 12c Enterprise Edition Release 12.1.0.2.0
Connected as test#soft12c1
SQL> create table mail_1 (email varchar2(100));
Table created
SQL> create table mail_2 (email varchar2(100));
Table created
SQL> create trigger mail_1_check
2 before insert on mail_1
3 for each row
4 declare
5 cnt integer;
6 begin
7 select count(*) into cnt from mail_2 where email = :new.email;
8 if cnt > 0 then
9 raise_application_error(-20100, 'Email already exists');
10 end if;
11 end;
12 /
Trigger created
SQL> insert into mail_2 values ('president#gov.us');
1 row inserted
SQL> insert into mail_1 values ('king#kingdom.en');
1 row inserted
SQL> insert into mail_1 values ('president#gov.us');
ORA-20100: Email already exists
ORA-06512: at "TEST.MAIL_1_CHECK", line 6
ORA-04088: error during execution of trigger 'TEST.MAIL_1_CHECK'
It looks like trigger works right, but it's not true. See what happens when several users will works simultaneously.
-- First user in his session
SQL> insert into mail_2 values ('dictator#country.by');
1 row inserted
-- Second user in his session
SQL> insert into mail_1 values ('dictator#country.by');
1 row inserted
-- First user is his session
SQL> commit;
Commit complete
-- Second user is his session
SQL> commit;
Commit complete
-- Any user in any session
SQL> select * from mail_1 natural join mail_2;
EMAIL
--------------------------------------------------------------------------------
dictator#country.by
If using triggers for this task, you should serialize any attempts to use this data, say, execute LOCK TABLE IN EXCLUSIVE MODE unless commit. Generally it's a bad decision. For this concrete task you can use much better approach:
Connected to Oracle Database 12c Enterprise Edition Release 12.1.0.2.0
Connected as test#soft12c1
SQL> create table mail_1_2nd(email varchar2(100));
Table created
SQL> create table mail_2_2nd(email varchar2(100));
Table created
SQL> create materialized view mail_check
2 refresh complete on commit
3 as
4 select 1/0 data from mail_1_2nd natural join mail_2_2nd;
Materialized view created
OK. Let's see, what if we try to use same email:
-- First user in his session
SQL> insert into mail_1_2nd values ('dictator#gov.us');
1 row inserted
-- Second user in his session
SQL> insert into mail_2_2nd values ('dictator#gov.us');
1 row inserted
SQL> commit;
Commit complete
-- First user in his session
SQL> commit;
ORA-12008: error in materialized view refresh path
ORA-01476: divisor is equal to zero
SQL> select * from mail_1_2nd natural join mail_2_2nd;
EMAIL
--------------------------------------------------------------------------------
no rows selected

Roll back Update or delete data Through Flashback query

I have done some changes and commited but i want to roll back those changes through Flashback query.
Can you please help me how to do this?
I am using Oracle 11g Version.
From below tables i have deleted the data..Now i want to revert back those records..
Customer,
Address,
Employee,
Alignemnt
Many Thanks for your help.
Sunitha.
There are two things,
1.Flashback by SCN
SELECT column_list
FROM table_name
AS OF SCN scn_number;
2.Flashback by TIMESTAMP
SELECT column_list
FROM table_name
AS OF TIMESTAMP TO_TIMESTAMP('the timestamp value');
To get current_scn and systimestamp, query :
SELECT current_scn, SYSTIMESTAMP
FROM v$database;
Update Example as requested by OP.
To flashback the table to the old scn, use FLASHBACK TABLE..TO SCN clause.
SQL> DROP TABLE string_ex PURGE;
Table dropped.
SQL> CREATE TABLE string_ex (sl_ps_code VARCHAR2(20) );
Table created.
SQL> INSERT INTO string_ex (sl_ps_code) VALUES ('AR14ASM0002');
1 row created.
SQL> INSERT INTO string_ex (sl_ps_code) VALUES ('AR14SFT0018');
1 row created.
SQL> INSERT INTO string_ex (sl_ps_code) VALUES ('AR14SFT0019');
1 row created.
SQL> INSERT INTO string_ex (sl_ps_code) VALUES ('AR14SFT0062');
1 row created.
SQL> COMMIT;
Commit complete.
SQL> SELECT current_scn, SYSTIMESTAMP FROM v$database;
CURRENT_SCN SYSTIMESTAMP
-------------------- --------------------------------------------
13818123201277 29-OCT-14 03.02.17.419000 PM +05:30
SQL> SELECT current_scn, SYSTIMESTAMP FROM v$database;
CURRENT_SCN SYSTIMESTAMP
-------------------- --------------------------------------------
13818123201280 29-OCT-14 03.02.22.785000 PM +05:30
SQL> SELECT current_scn, SYSTIMESTAMP FROM v$database;
CURRENT_SCN SYSTIMESTAMP
-------------------- --------------------------------------------
13818123201282 29-OCT-14 03.02.26.781000 PM +05:30
SQL> SELECT * FROM string_ex;
SL_PS_CODE
---------------
AR14ASM0002
AR14SFT0018
AR14SFT0019
AR14SFT0062
SQL>
I have four rows in the table.
SQL> ALTER TABLE string_ex ENABLE ROW MOVEMENT;
Table altered.
SQL>
Row movement is required.
SQL> DELETE FROM string_ex WHERE ROWNUM =1;
1 row deleted.
SQL>
SQL> COMMIT;
Commit complete.
SQL>
SQL> SELECT * FROM string_ex;
SL_PS_CODE
---------------
AR14SFT0018
AR14SFT0019
AR14SFT0062
I deleted a row now and committed the changes.
SQL> FLASHBACK TABLE string_ex TO SCN 13818123201277;
Flashback complete.
Flashback is complete
SQL> SELECT * FROM string_ex;
SL_PS_CODE
---------------
AR14ASM0002
AR14SFT0018
AR14SFT0019
AR14SFT0062
SQL>
I now have my table to old state and the row is back