I'm inserting data into table with date value, how to add to inserting date value current system time in format HH:MM
My insert
INSERT INTO tab1 VALUES to_date('11-OCT-2021');
I wanna insert '11-OCT-2021 22:08' where 22:08 current system time. How to do it
Thx
You can use:
INSERT INTO tab1 (column_name)
VALUES ( DATE '2021-10-11' + (SYSDATE - TRUNC(SYSDATE)) );
or
INSERT INTO tab1 (column_name)
VALUES (
TO_DATE(
'11-OCT-2021' || TO_CHAR(SYSDATE, 'HH24:MI:SS'),
'DD-MON-YYYYHH24:MI:SS',
'NLS_DATE_LANGUAGE=American'
)
);
db<>fiddle here
Here's one option:
SQL> create table tab1 (datum date);
Table created.
SQL> insert into tab1 values (date '2021-10-11');
1 row created.
SQL> select * from tab1;
DATUM
-------------------
11.10.2021 00:00:00
SQL> update tab1 set datum = to_date(to_char(datum, 'dd.mm.yyyy') || to_char(sysdate, 'hh24:mi'), 'dd.mm.yyyy hh24:mi');
1 row updated.
SQL> select * from tab1;
DATUM
-------------------
11.10.2021 21:47:00
SQL>
On the other hand, why wouldn't you insert the "whole" value immediately?
SQL> rollback;
Rollback complete.
SQL> insert into tab1 values (sysdate);
1 row created.
SQL> select * from tab1;
DATUM
-------------------
12.10.2021 21:48:21
SQL>
Related
I would like to create a Trigger in Oracle, in order to check the Current Date with the Date that is stored in a specific column and if they are equal, I would like to change a boolean value on the same table. I am new to Oracle and especially on creating triggers. Any help is much appreciated.
CREATE TABLE DISCIPLINARYAUDIT
(
DISCIPLINARYAUDITID NUMBER(19, 0) NOT NULL
, DISCIPLINARYAUDITTYPE VARCHAR2(255 CHAR) NOT NULL
, REVOCATIONORCOMPLETION NUMBER(1, 0)
, STARTDATE DATE
, ENDDATE DATE
)
When endDate equals with current Date, RevocationORCompletion must chenage from 0 to 1.
Thank you in advance.
Here's an example.
Date format and today's date:
SQL> alter session set nls_date_format = 'dd.mm.yyyy';
Session altered.
Sample table:
SQL> create table test (id number, specific_column date, boolean_column varchar2(10));
Table created.
SQL> insert into test values (1, trunc(sysdate), 'FALSE');
1 row created.
SQL> insert into test values (2, trunc(sysdate) - 2, 'FALSE');
1 row created.
SQL> select * from test order by id;
ID SPECIFIC_C BOOLEAN_CO
---------- ---------- ----------
1 04.06.2020 FALSE
2 02.06.2020 FALSE
Trigger:
SQL> create or replace trigger trg_biu_test
2 before insert or update on test
3 for each row
4 begin
5 if :new.specific_column = trunc(sysdate) then
6 :new.boolean_column := 'TRUE';
7 end if;
8 end;
9 /
Trigger created.
Testing:
SQL> update test set id = 3 where id = 1;
1 row updated.
SQL> update test set id = 5 where id = 2;
1 row updated.
SQL> select * from test;
ID SPECIFIC_C BOOLEAN_CO
---------- ---------- ----------
3 04.06.2020 TRUE
5 02.06.2020 FALSE
SQL>
I am a developer. In my table, I had a date range partitions.
I want to get partition names which are defined for a table between two dates.
I tried with below query and it is returning all the partitions on a table.
select * from USER_TAB_PARTITIONS WHERE TABLE_NAME = 'TABLE NAME' ORDER BY PARTITION_NAME;
My requirement is , I will pass two dates as inputs and between those two dates i want to get partition names.
Please suggest query.
That's not very simple; the major obstacle is user_tab_partitions.high_value datatype, which is long, and it is difficult to work with. Usually you get
ORA-00932: inconsistent datatypes: expected - got LONG
error.
However, using a few steps, it can be done. Have a look at this example.
Create a partitioned table and insert a few rows into it:
SQL> CREATE TABLE test_part
2 (
3 datum DATE,
4 text VARCHAR2 (10)
5 )
6 PARTITION BY RANGE (datum)
7 INTERVAL ( NUMTODSINTERVAL (1, 'day') )
8 (PARTITION p0 VALUES LESS THAN (TO_DATE ('01.01.2020', 'dd.mm.yyyy')));
Table created.
SQL> INSERT INTO test_part
2 SELECT DATE '2015-08-15', 'Little' FROM DUAL
3 UNION ALL
4 SELECT DATE '2020-03-26', 'Foot' FROM DUAL;
2 rows created.
What does user_tab_partitions say?
SQL> SELECT table_name, partition_name, high_value
2 FROM user_tab_partitions
3 WHERE table_name = 'TEST_PART';
TABLE_NAME PARTITION_NAME HIGH_VALUE
--------------- --------------- -----------------------------------
TEST_PART P0 TO_DATE(' 2020-01-01 00:00:00', 'SY
YYY-MM-DD HH24:MI:SS', 'NLS_CALENDA
R=GREGORIA
TEST_PART SYS_P63 TO_DATE(' 2020-03-27 00:00:00', 'SY
YYY-MM-DD HH24:MI:SS', 'NLS_CALENDA
R=GREGORIA
So, you'd want to extract date part from the high_value column. The first step is kind of a stupid one - create a new table; basically CTAS:
SQL> CREATE TABLE temp_utp
2 AS
3 SELECT table_name, partition_name, TO_LOB (high_value) high_value
4 FROM user_tab_partitions;
Table created.
For simplicity (in further steps), I'll create a view based on that table which will extract date value (line #5):
SQL> CREATE OR REPLACE VIEW v_utp
2 AS
3 SELECT table_name,
4 partition_name,
5 TO_DATE (SUBSTR (high_value, 12, 10), 'rrrr-mm-dd') datum
6 FROM temp_utp;
View created.
The rest is easy now:
SQL> SELECT *
2 FROM v_utp
3 WHERE datum < DATE '2020-02-15';
TABLE_NAME PARTITION_NAME DATUM
--------------- --------------- ----------
TEST_PART P0 2020-01-01
SQL>
OK, you'd use two date parameters which would then lead to between in the final query, but that's easy to modify.
Major drawback here is CTAS which creates temp_utp table; you'd have to recreate it as frequently as you add new partitions into the main table. One option is to do it in a scheduled manner, e.g. using a database job (see dbms_job and/or dbms_scheduler documentation if you don't know how) which would schedule a stored procedure which will then use dynamic SQL, i.e. execute immediate to create temp_utp. You don't have to recreate a view - it will become valid as soon as a new temp_utp table is created.
I was trying to find solution for the same problem and found that creating a function to convert high value to date works fine like below
CREATE OR REPLACE FUNCTION get_high_value_date(p_partition_name IN VARCHAR2)
RETURN DATE
IS
l_varchar_date VARCHAR2(4000);
l_date DATE;
BEGIN
EXECUTE IMMEDIATE 'SELECT high_value FROM all_tab_partitions WHERE partition_name = :1 ' INTO l_varchar_date
USING p_partition_name;
EXECUTE IMMEDIATE 'SELECT '||l_varchar_date||' FROM dual' INTO l_date;
RETURN l_date;
EXCEPTION WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE ( 'Exc: '||SQLERRM );
RETURN NULL;
END;
Then you can use this for getting date value
SELECT get_high_value_date (partition_name) partition_date, partition_name
FROM all_tab_partitions
WHERE table_name = :table
I am trying to get all the new values and old values in trigger before inserting it to another table but i could just get the specific value not the all the data.
I tried with :NEW.* and :OLD.* it works fine for postgress but not for oracle.
CREATE OR REPLACE TRIGGER trg_customer_tbl_ib01
BEFORE INSERT OR UPDATE OR DELETE ON TEST.customer_test
FOR EACH ROW
DECLARE
vAction VARCHAR2(4000) := null;
vFound INT := null;
vREC TEST.CUSTOMER_TEST%ROWTYPE;
BEGIN
IF INSERTING OR UPDATING THEN
select :NEW.* into vREC FROM DUAL;
ELSIF DELETING THEN
select :OLD.* into vREC FROM DUAL;
END IF;
IF DELETING THEN
INSERT INTO TEST.CUSTOMER_TEST_AUDIT SELECT
CUSTOMER_TEST_AUDIT_id_seq.NEXTVAL,'D',SYSDATE, vREC.* FROM DUAL;
ELSIF UPDATING THEN
INSERT INTO TEST.CUSTOMER_TEST_AUDIT SELECT
CUSTOMER_TEST_AUDIT_id_seq.NEXTVAL,'U',SYSDATE, vREC.*FROM DUAL;
ELSIF INSERTING THEN
INSERT INTO TEST.CUSTOMER_TEST_AUDIT SELECT
CUSTOMER_TEST_AUDIT_id_seq.NEXTVAL,'I',SYSDATE, vREC.* FROM DUAL;
END IF;
END;
I am getting error :
Error(10,8): PLS-00049: bad bind variable 'NEW.'
Well, don't be impatient. Don't use shortcuts.
Test case:
SQL> create table test as select * From dept;
Table created.
SQL> create table test_log as select * From dept where 1 = 2;
Table created.
SQL> alter table test_log add (id number, action varchar2(1), datum date);
Table altered.
SQL> create sequence seqlog;
Sequence created.
SQL>
Trigger. Reference each column separately. The fact that :NEW.* works in Postgres doesn't mean it works in Oracle.
SQL> create or replace trigger trg_test
2 before insert or update or delete on test
3 for each row
4 begin
5 if updating then
6 insert into test_log (deptno, dname, loc, id, action, datum)
7 values
8 (:old.deptno, :old.dname, :old.loc, seqlog.nextval, 'U', sysdate);
9 insert into test_log (deptno, dname, loc, id, action, datum)
10 values
11 (:new.deptno, :new.dname, :new.loc, seqlog.nextval, 'U', sysdate);
12 elsif inserting then
13 insert into test_log (deptno, dname, loc, id, action, datum)
14 values
15 (:new.deptno, :new.dname, :new.loc, seqlog.nextval, 'I', sysdate);
16 elsif deleting then
17 insert into test_log (deptno, dname, loc, id, action, datum)
18 values
19 (:old.deptno, :old.dname, :old.loc, seqlog.nextval, 'D', sysdate);
20 end if;
21 end;
22 /
Trigger created.
SQL>
Testing:
SQL> alter session set nls_Date_format = 'dd.mm.yyyy hh24:mi:ss';
Session altered.
SQL> update test set loc = 'Croatia' where deptno = 10;
1 row updated.
SQL> delete from test where deptno = 20;
1 row deleted.
SQL> insert into test (deptno, dname, loc) values (99, 'IT', 'Zagreb');
1 row created.
SQL> select * From test_log order by id;
DEPTNO DNAME LOC ID A DATUM
---------- -------------- ------------- ---------- - -------------------
10 ACCOUNTING NEW YORK 5 U 20.05.2019 21:44:33
10 ACCOUNTING Croatia 6 U 20.05.2019 21:44:33
20 RESEARCH DALLAS 7 D 20.05.2019 21:44:43
99 IT Zagreb 8 I 20.05.2019 21:44:52
SQL>
Is it possible to check the count of a table before any changes happen and the count after the insert and match them inside the same trigger?
for ex: old.count and new.count (before and after insert) ?
old.count and new.count (before and after insert)
Nothing stops you from using SELECT COUNT(*) in a before insert trigger. Of course, you won't do it in a after insert trigger, since a select count(*) on the same table on which an after trigger is defined would throw mutating table error. One way is autonomous transaction. But, in your case, it isn't that complex.
You could define a BEFORE INSERT TRIGGER and take the table count. The after insert count could be taken manually after the actual insert is done.
For example, I have a table t1 with one row. I have defined a before insert trigger on it, which would give me the table count before the insert happens.
SQL> DROP TABLE t1 PURGE;
Table dropped.
SQL>
SQL> CREATE TABLE t1 (A NUMBER);
Table created.
SQL>
SQL> INSERT INTO t1 VALUES (1);
1 row created.
SQL>
SQL> SELECT * FROM t1;
A
----------
1
SQL>
SQL> CREATE OR REPLACE TRIGGER trg
2 BEFORE INSERT
3 ON t1
4 FOR EACH ROW
5
6 DECLARE
7 val number;
8 BEGIN
9 SELECT COUNT(*)
10 INTO val
11 FROM t1;
12
13 DBMS_OUTPUT.PUT_LINE('TABLE COUNT BEFORE INSERT = '||val);
14
15 END;
16 /
Trigger created.
SQL>
SQL> set serveroutput on
SQL> INSERT INTO t1 VALUES (1);
TABLE COUNT BEFORE INSERT = 1
1 row created.
SQL>
SQL> SELECT COUNT(*) FROM t1;
COUNT(*)
----------
2
SQL>
So, you see TABLE COUNT BEFORE INSERT = 1 and then after insert the count is 2.
I get some strange behaviour.
I have a procedure which changes in the names of partitions in a table.
I created a job which runs this procedure every 2 mins for testing.
First run goes very smooth and without any error so far.
However, from 2nd run I get the following error
"ORA-00054: resource busy and acquire with NOWAIT specified or timeout expired
ORA-06512: at "CDS_USER.RENAMING_PARTITIONS", line 17"
Yes, My table is live. But when I run my procedure explicitly withoug the scheduler, it runs perfectly fine. No issues with that. And every first run by the scheduler is also perfect.
Here is the code for scheduler
begin
bms_Scheduler.create_job(
job_name => 'drop_user1' ,
job_action => 'RENAMING_PARTITIONS'
job_action => 'DROP_PARTITIONS'
,start_date => SYSDATE ,
repeat_interval => 'freq=hourly;INTERVAL=7',bysecond=0;' ,
enabled => TRUE ,
comments => 'schduling drop job.');
END;
Here is the code for procedure
create or replace PROCEDURE RENAMING_PARTITIONS
AS
hv varchar2(9);
max_part VARCHAR2(9);
begin
select max(partition_position) into max_part from user_tab_partitions where table_name='DEMO';
for x in (select partition_name, high_value, partition_position
from user_tab_partitions
where table_name = 'DEMO' and partition_name like 'SYS%')
loop
if x.partition_position <> max_part THEN
execute immediate 'select to_char('||x.high_value||'-1,''YYYYMMDD'') from dual' into hv;
partition '||x.partition_name
--||' to DATE_'||hv);
execute immediate('alter table DEMO rename partition '||x.partition_name
||' to DATE_'||hv);
end if;
end loop;
end;
How can I fix this?
Don't do this. I know its inconvenient that Oracle won't follow a predefined partition naming schema for system created interval partitions (probably an enhancement to come in future), but altering the table every 2 min is not a good alternative by any stretch.
Luckily, you really only need to know the partition name in advance when specifying it in queries. The typical query would be something like:
select * from my_table partition (blah);
In 11g, you can use the "partition for" clause to workaround the system generated names, as follows (example for interval DATE partitions):
SQL> set display on
SQL> set linesize 200
SQL> drop table test_data
Table dropped.
SQL> create table test_data (
start_date DATE,
store_id NUMBER,
inventory_id NUMBER,
qty_sold NUMBER
)
PARTITION BY RANGE (start_date)
INTERVAL(NUMTOYMINTERVAL(1, 'MONTH'))
(
PARTITION part_01 values LESS THAN (TO_DATE('20130101','YYYYMMDD'))
)
Table created.
SQL> insert into test_data values (to_date('20121231', 'YYYYMMDD'), 1, 2, 1)
1 row created.
SQL> commit
Commit complete.
SQL> SELECT table_name, partition_name, high_value
FROM user_tab_partitions
WHERE table_name = 'TEST_DATA'
ORDER BY table_name, partition_name
TABLE_NAME PARTITION_NAME HIGH_VALUE
------------------------------ ------------------------------ --------------------------------------------------
TEST_DATA PART_01 TO_DATE(' 2013-01-01 00:00:00', 'SYYYY-MM-DD HH24:
MI:SS', 'NLS_CALENDAR=GREGORIAN')
1 row selected.
SQL> insert into test_data values (to_date('20130101', 'YYYYMMDD'), 1, 5, 8)
1 row created.
SQL> insert into test_data values (to_date('20130115', 'YYYYMMDD'), 2, 4, 5)
1 row created.
SQL> insert into test_data values (sysdate, 2, 3, 2)
1 row created.
SQL> commit
Commit complete.
SQL> SELECT table_name, partition_name, high_value
FROM user_tab_partitions
WHERE table_name = 'TEST_DATA'
ORDER BY table_name, partition_name
TABLE_NAME PARTITION_NAME HIGH_VALUE
------------------------------ ------------------------------ --------------------------------------------------
TEST_DATA PART_01 TO_DATE(' 2013-01-01 00:00:00', 'SYYYY-MM-DD HH24:
MI:SS', 'NLS_CALENDAR=GREGORIAN')
TEST_DATA SYS_P67 TO_DATE(' 2013-02-01 00:00:00', 'SYYYY-MM-DD HH24:
MI:SS', 'NLS_CALENDAR=GREGORIAN')
TEST_DATA SYS_P68 TO_DATE(' 2013-03-01 00:00:00', 'SYYYY-MM-DD HH24:
MI:SS', 'NLS_CALENDAR=GREGORIAN')
3 rows selected.
SQL> -- get data for January partition only
SQL> select * from test_data partition for (to_date('20130101', 'YYYYMMDD'))
START_DATE STORE_ID INVENTORY_ID QTY_SOLD
----------- ---------- ------------ ----------
01-JAN-2013 1 5 8
15-JAN-2013 2 4 5
2 rows selected.