Stored Procedure - Error When Converting Date - oracle

My stored procedure is failing, I am trying to convert the time stamp to a date.
create or replace PROCEDURE "USP_CLEAN_FOBTPP"
AS
BEGIN
INSERT INTO CLN_FOBTPP
SELECT PART_PAYMENT_ID,
ISSUING_SHOP,
TILL_NUMBER,
SLIP_NUMBER,
FOBT_NUMBER,
WHO_PAID,
to_date(WHEN_PAID,'DD-MON-YY HH24:MI:SS'),
AMOUNT_LEFT_TO_PAY,
FOBT_VALUE,
STATUS
FROM IMPORTDB.IMP_FOBTPP;
COMMIT;
END;
The is the error I get:
ORA-01830: date format picture ends before converting entire input
string.
This is the format of the When_Paid date column
11-OCT-17 13.29.20.000000000
11-OCT-17 13.30.21.000000000
11-OCT-17 13.31.11.000000000
11-OCT-17 12.56.39.000000000
11-OCT-17 12.57.28.000000000
11-OCT-17 12.57.46.000000000
What is going wrong?
Source Table IMPORTDB.IMP_FOBT
Name Null? Type
------------------ ----- ------------
PART_PAYMENT_ID NUMBER(38)
ISSUING_SHOP CHAR(4)
TILL_NUMBER NUMBER(3)
SLIP_NUMBER NUMBER(38)
FOBT_NUMBER VARCHAR2(30)
WHO_PAID CHAR(20)
WHEN_PAID TIMESTAMP(6)
AMOUNT_LEFT_TO_PAY NUMBER(19,4)
FOBT_VALUE NUMBER(19,4)
STATUS CHAR(2)
Destination Table IMPORTDB.CLN_FOBTPP
Name Null? Type
------------------ -------- ------------
PART_PAYMENT_ID NOT NULL VARCHAR2(4)
ISSUING_SHOP NOT NULL VARCHAR2(4)
TILL_NUMBER NOT NULL NUMBER(3)
SLIP_NUMBER NOT NULL VARCHAR2(4)
FOBT_NUMBER NOT NULL VARCHAR2(30)
WHO_PAID NOT NULL CHAR(20)
WHEN_PAID NOT NULL DATE
AMOUNT_LEFT_TO_PAY NOT NULL NUMBER(19,4)
FOBT_VALUE NOT NULL NUMBER(19,4)
STATUS NOT NULL CHAR(2)
This is the table structure.

If the stored data is in timestamp data type, what you need is a CAST, not TO_DATE:
...
, cast (when_paid as date) , ...
EDIT: In a Comment below this Answer, the OP says he is getting an error about the hour having to be between 1 and 12. Not sure what the OP is doing wrong; to prove that is NOT the case for the cast function in Oracle, here is an illustration:
with input (ts) as (
select to_timestamp('11-OCT-17 15:35:24.000000000', 'dd-MON-rr hh24:mi:ss.ff')
from dual
)
select ts, cast(ts as date) as dt
from input;
TS DT
---------------------------- -------------------
11-OCT-17 15.35.24.000000000 2017-10-11 15:35:24

You are trying to convert a TIMESTAMP column with TO_DATE to insert into a DATE column - which is not necessary. This works perfectly.
create table source1 ( t TIMESTAMP );
create table dest1 ( t DATE );
INSERT INTO source1 VALUES(SYSTIMESTAMP);
INSERT INTO dest1 SELECT * FROM source1;
PS: change this line to_date(WHEN_PAID,'DD-MON-YY HH24:MI:SS') to WHEN_PAID,

Related

Oracle INSERTING into RAW with UTL_RAW.cast_to_raw

I ran into some code that was never implemented (see below).
CREATE TABLE encryption_values
(
NAME VARCHAR2(6),
VALUE NVARCHAR2(100)
);
/
insert into encryption_values
select 'key' name,
rawtohex (
rpad ('52AB32;^$!ER94988OPS3W21##=WTQ32',32,'X')
) value
from dual
union
select 'iv' name,
rawtohex (
rpad ('TY54ABCX12#÷×+==643QREVDG43AAYMN',32,'X')
) value
from dual;
I want to change the table definition from NVARCHAR2(100) to RAW(256). I tried using
UTL_RAW.cast_to_raw()
but I'm running into some syntax errors. Can someone please provide me with the correct syntax. Note I want to keep the RPAD to ensure I'm converting 32 character bytes.
I'm looking to INSERT the data into this table definition.
CREATE TABLE encryption_values
(
NAME VARCHAR2(6),
VALUE RAW(256)
);
/
You are using the wrong function, rawtohex. You must use in your case cast_to_raw from the package utl_raw
This function converts a VARCHAR2 value represented using some number
of data bytes into a RAW value with that number of data bytes. The
data itself is not modified in any way, but its datatype is recast to
a RAW datatype.
Demo
SQL> desc encryption_values
Name Null? Type
----------------------------------------- -------- ----------------------------
NAME VARCHAR2(6)
VALUE RAW(256)
SQL> insert into encryption_values
2 select 'key' name,
3 utl_raw.cast_to_raw (rpad('52AB32;^$!ER94988OPS3W21##=WTQ32',32,'X')) value
4 from dual
5 union
6 select 'iv' name,
7 utl_raw.cast_to_raw (rpad('TY54ABCX12#÷×+==643QREVDG43AAYMN',32,'X')) value
8* from dual
SQL> /
2 rows created.
SQL> select * from encryption_values ;
NAME
------
VALUE
--------------------------------------------------------------------------------
iv
5459353441424358313240EFBFBDEFBFBDEFBFBDEFBFBD2B3D3D3634335152455644473433414159
key
3532414233323B5E2421455239343938384F50533357323140403D5754513332

I need added automatic calculation for “AGE” attribute that need to be calculated in oracle

if i have “INSERT INTO” i need added automatic calculation for “AGE” attribute that need to be calculated
I've tried
create or replace TRIGGER AGE_CALC03 BEFORE INSERT OR UPDATE ON EMPLOYEES
FOR EACH ROW BEGIN
:new.AGE := SYSDATE - :new.BIRTH_DATE;
END AGE_CALC03;”
Having an AGE column is a bad choice because it will become incorrect if the data in the row is not refreshed regularly.
However, I suspect this is a school assignment and you don't care about the design problems. OK - the reason your trigger isn't giving you a good value for AGE is that the calculation is simply wrong. You're subtracting one date from another, thinking that this will give you the difference in years. It does not - it gives you the difference in DAYS.
The correct calculation to use for AGE is FLOOR(MONTHS_BETWEEN(SYSDATE, BIRTH_DATE) / 12). So your trigger should read:
CREATE OR REPLACE TRIGGER AGE_CALC03
BEFORE INSERT OR UPDATE ON EMPLOYEES
FOR EACH ROW
BEGIN
:new.AGE := FLOOR(MONTHS_BETWEEN(SYSDATE, :new.BIRTH_DATE) / 12);
END AGE_CALC03;
But - back to the problems with an AGE column. A better way to obtain an employees age is to have a function to call which returns you a persons age based on their birth date. Something like the following:
FUNCTION COMPUTE_AGE(pinBirth_date IN DATE)
RETURN NUMBER
AS
BEGIN
RETURN FLOOR(MONTHS_BETWEEN(SYSDATE, pinBirth_date ) / 12)
END COMPUTE_AGE;
Then get rid of the AGE column on the EMPLOYEES table and call this function any time you need someone's age, which will then be correct at any given moment in time.
In Oracle 12 and later, use a virtual column and a deterministic function:
CREATE FUNCTION calculate_age(
birth_date DATE,
now_date DATE DEFAULT SYSDATE
) RETURN INTEGER DETERMINISTIC
IS
BEGIN
RETURN FLOOR( MONTHS_BETWEEN( now_date, birth_date ) / 12 );
END;
/
and:
CREATE TABLE EMPLOYEES (
EMPLOYEE_ID VARCHAR2(5 BYTE)
CONSTRAINT EMPLOYEES__EMPLOYEE_ID__NN NOT NULL
CONSTRAINT EMPLOYEES__EMPLOYEE_ID__PK PRIMARY KEY,
FIRST_NAME VARCHAR2(100 BYTE),
LAST_NAME VARCHAR2(100 BYTE),
IDENTIFICATION_NUMBER NUMBER(13,0),
MANAGER_ID VARCHAR2(5 BYTE)
CONSTRAINT EMPLOYEES__MANAGER_ID__FK REFERENCES EMPLOYEES ( EMPLOYEE_ID ),
DEPARTMENT_ID VARCHAR2(1 BYTE),
WORKING_STATUS VARCHAR2(1 BYTE),
BIRTH_DATE DATE,
AGE INTEGER
GENERATED ALWAYS AS ( calculate_age( BIRTH_DATE ) ) VIRTUAL
);
Then if you insert some sample data:
INSERT INTO EMPLOYEES ( EMPLOYEE_ID, BIRTH_DATE )
SELECT 'Alice', DATE '2000-01-01' FROM DUAL UNION ALL
SELECT 'Bob', DATE '1990-01-01' FROM DUAL UNION ALL
SELECT 'Carol', DATE '1980-01-01' FROM DUAL;
and query the ages:
SELECT Employee_id, birth_date, age FROM employees;
You get the output:
EMPLOYEE_ID | BIRTH_DATE | AGE
:---------- | :------------------ | --:
Alice | 2000-01-01 00:00:00 | 20
Bob | 1990-01-01 00:00:00 | 30
Carol | 1980-01-01 00:00:00 | 40
db<>fiddle here
If you already have the birth_date column in your system, Why do you have Age column too. This is redundancy of data. Whenever you need to show age you can simply use your logic as SYSDATE - BIRTH_DATE.
If you strictly need to use AGE column in your table, You have to use TRIGGER as you are currently using. Are you having any issues in doing so?

how can I insert date into table where it's null and date is by default sysdate in timestamp fomat?

Name Null Type
------------ -------- ------------
ID NOT NULL NUMBER
NAME VARCHAR2(20)
ADDRESS VARCHAR2(20)
CLASS VARCHAR2(10)
DATE_CREATED TIMESTAMP(6)
1 SATISH PUNE SOFTWARE
2 ABHISHEK INDORE BUSINESS
3 ARUN BARWANI GOVERNMENT
4 RITESH SHIVNI SOFTWARE
5 NAYAN BANGLORE SOFTWARE 27-12-19 07:23:45.000000000 PM
If you just want to select from your table including systimestamp for null values then use following select:
Select id, name, address, class,
Nvl(date_created, systimestamp)
From your_table;
If you want to update the date_created in table then use following update:
Update your_table
Set date_created = systimestamp
Where date_created is null;
Cheers!!

From string in 24 hours to timestamp

I have a table with one column giving me dates in the form 24-JUL-17 and another column a string telling me the hour in the form hh:mm:ss.several_decimals but they are in 24 hours and not AM/PM, could someone point me on how I can add a column in oracle that combines them both into a timestamp?
CAST the date to a timestamp data type and use TO_DSINTERVAL to convert the time column to a DAY TO SECOND INTERVAL and then add one to the other:
SQL Fiddle
Oracle 11g R2 Schema Setup:
CREATE TABLE table_name (
date_column DATE,
time_column VARCHAR2(15)
);
INSERT INTO table_name ( date_column, time_column )
VALUES ( DATE '2017-06-24', '12:34:56.789012' );
Query 1:
SELECT CAST( date_column AS TIMESTAMP )
+ TO_DSINTERVAL( '+0 ' || time_column ) AS datetime
FROM table_name
Results:
| DATETIME |
|----------------------------|
| 2017-06-24 12:34:56.789012 |
Here is an example with a fabricated table.
WITH test_data AS (
SELECT
SYSDATE date_val,
'14:23:15.123' AS time_val
FROM
dual
) SELECT
to_timestamp(TO_CHAR(date_val,'MM/DD/YYYY')
|| ' '
|| time_val,'MM/DD/YYYY HH24:MI:SS.FF3')
FROM
test_data
Just concatenate both input strings with || and convert it with TO_TIMESTAMP. The format is a bit tricky, took me a while to get it right.
CREATE TABLE mytable (mydate VARCHAR2(9), mytime VARCHAR2(20), mytimestamp TIMESTAMP);
INSERT INTO mytable (mydate, mytime) VALUES ('24-JUL-17', '22:56:47.1915010');
Test it
SELECT TO_TIMESTAMP(mydate||mytime, 'DD-MON-YYHH24:MI:SS.FF9') FROM mytable;
2017-07-24 22:56:47,191501000
Or, in a table:
UPDATE mytable
SET mytimestamp = TO_TIMESTAMP(mydate||mytime, 'DD-MON-YYHH24:MI:SS.FF9');

How can I load data conditionally using sqlldr in oracle

I have a txt file as follows. 1st machine_no,2nd emp_no, 3rd shift_type (1 for entry,3 for exit), 4th work_date, 4th is time.
001,0000000021,01,2011/06/21,06:50,
001,0000000026,01,2011/06/21,14:00,
001,0000000018,01,2011/06/21,07:00,
001,0000000021,03,2011/06/21,14:00,
001,0000000018,03,2011/06/21,16:50,
001,0000000026,03,2011/06/21,16:55,
I want to load data in the table. The field time1 to have time if
time_type is 1 and the field time2 to have time if time_type is
3. Please let me know how I can have this in the control file.
Thanks in advance for your help..Macky.
Below is the txt file and table in oracle.
The table as follows:
desc data_trans;
Name Null? Type
------------------------------- -------- ----
MACHIAN VARCHAR2(4)
YEAR NUMBER(4)
MONTH VARCHAR2(2)
WDAY VARCHAR2(2)
TIME1 VARCHAR2(5)
TIME2 VARCHAR2(5)
TIME3 VARCHAR2(2)
SHIFT_NO NUMBER(1)
TIME_TYPE NUMBER(1)
WORK_DATE DATE
EMP_NO VARCHAR2(10)
Why don't you use an external table to read this file and then you can simply SELECT from it and perform any conditional transformation you want to easily in SQL.
N.B. There are a few assumptions, you seem to interchange "time_type" with what seems to be "shift_type" and there are table columns that are not present in your data file etc.
-- Create the Oracle directory
CREATE OR REPLACE DIRECTORY file_dir AS '<physical-server-directory-path>';
-- Grant privs on the directory
GRANT READ, WRITE ON DIRECTORY file_dir TO <username>;
-- Create the external table
CREATE TABLE ext_data_table
(machine_no VARCHAR2(4),
emp VARCHAR2(10),
shift_type VARCHAR2(2),
work_date VARCHAR2(10),
time VARCHAR2(5)
)
ORGANIZATION EXTERNAL (
DEFAULT DIRECTORY file_dir
ACCESS PARAMETERS(RECORDS DELIMITED BY NEWLINE
BADFILE file_dir :'file.bad'
LOGFILE file_dir :'file.log'
DISCARDFILE file_dir :'file.dsc'
FIELDS TERMINATED BY ','
(
machine_no CHAR(4),
emp CHAR(10),
shift_type CHAR(2),
work_date CHAR(10),
time CHAR(5)
)
LOCATION (
FILE_DIR:'<filename>'
)
)
NOPARALLEL;
-- Insert (and transform) your file data
INSERT INTO data_trans
(machian,
year,
month,
wday,
time1,
time2,
time3,
shift_no,
time_type,
work_date,
emp_no)
SELECT machine_no, -- machian
SUBSTR(work_date, 1, 4), -- year
SUBSTR(work_date, 6, 2), -- month
SUBSTR(work_date, 9, 2), -- wday
(CASE TO_NUMBER(shift_type)
WHEN 1
THEN time
ELSE NULL
END), -- time1
(CASE TO_NUMBER(shift_type)
WHEN 3
THEN time
ELSE NULL
END), -- time2
NULL, -- time3 (You don't specify)
NULL, -- shift_no (You don't specify)
TO_NUMBER(shift_type), -- time_type
TO_DATE(work_date, 'YYYY/MM/DD'), -- work_date
emp -- emp_no
FROM ext_data_table;
From the info given this is a close approximation.
Hope it helps.
This is not possible in SQL*Loader. Use an External Table, then copy it into your real table using the decode function to pivot.

Resources