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.
Related
I have the following table definition, with data that creates fine but I like to convert it to a more generic format but I'm having issues. Can someone point me in the right direction
CREATE TABLE partition_retention
(
seq_num NUMBER GENERATED BY DEFAULT AS IDENTITY (START WITH 1) NOT NULL,
TABLE_NAME VARCHAR2(30),
DAYS NUMBER(6),
CONSTRAINT
partition_retention_pk primary key (table_name));
/
INSERT into partition_retention(TABLE_NAME, DAYS)
WITH data as (
select 'T1', 0
from dual union all
select 'T3', 15
from dual union all
select 'T4', 10
from dual union all
select 'T5', 5
from dual)
SELECT * from data;
/
-- having problem creating
CREATE TABLE PARTITION_RETENTION AS (
TABLE_NAME AS VARCHAR2(30)
RETENTION DAY AS INTERVAL DAY(3) TO SECOND(0)
);
The three AS keywords are invalid (create table .. as select .. is valid, but you aren't doing that); you are missing a comma; and you have an unquoted column name with a space.
Correcting those things, this works:
CREATE TABLE PARTITION_RETENTION (
TABLE_NAME VARCHAR2(30),
RETENTION_DAY INTERVAL DAY(3) TO SECOND(0)
);
Your inserts will then have to insert interval values, not simple numbers, obviously.
db<>fiddle
how can I add a CONSTRAINT on the table to ensure the day>0 and the time is always 0
You can add separate constraints to check both things:
CREATE TABLE PARTITION_RETENTION (
TABLE_NAME VARCHAR2(30),
RETENTION_DAY INTERVAL DAY(3) TO SECOND(0),
CONSTRAINT CHK_NON_ZERO_DAYS CHECK (
RETENTION_DAY > INTERVAL '0' DAY
),
CONSTRAINT CHK_WHOLE_DAYS CHECK (
EXTRACT(HOUR FROM RETENTION_DAY) = 0
AND EXTRACT(MINUTE FROM RETENTION_DAY) = 0
AND EXTRACT(SECOND FROM RETENTION_DAY) = 0
)
);
to give slightly different errors (via the constraint names) - db<>fiddle - or combine them into one.
I'm not sure this is really any clearer or easier than having a number column constrained to integers between 1 and 999.
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?
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,
I'm doing an evaluation of FLYWAY and running a very simple script that creates a new table and insert a row to that table. The table creates successfully but I get an ORA-942 error on the INSERT. I have tried every permutation I can think of using upper/lower case and quoted and unquoted schema and table names. I have also tried separating out the INSERT statement into different script from the CREATE statement - all to no avail. Can anyone help explain the format flyway needs for the INSERT statements?
Here are the statements from my most recent attempt. I have tried the same statements with quotes around the table_name, with all lower case, with no quotes around the schema - nothing works. Logged directly into the database as SYS, I can describe the table with this command:
desc "FLYWAY_USER".department
CREATE TABLE "FLYWAY_USER".DEPARTMENT
( DEPARTMENT_id NUMBER(3) NOT NULL,
DEPARTMENT VARCHAR2(64) NOT NULL,
display_name VARCHAR2(64) NOT NULL,
description VARCHAR2(400),
create_date DATE NOT NULL,
update_date DATE NOT NULL,
created_by VARCHAR2(80) NOT NULL,
updated_by VARCHAR2(80) NOT NULL )
TABLESPACE users;
INSERT INTO "FLYWAY_USER".DEPARTMENT
( DEPARTMENT_id,
DEPARTMENT,
display_name,
description,
create_date,
update_date,
created_by,
updated_by )
VALUES
( ( SELECT Nvl( Max(DEPARTMENT_id), 0) + 1 FROM DEPARTMENT ),
'HUMAN_RESOURCES',
'Human Resources',
'The best place to eat smores or get a raise.',
Sysdate,
Sysdate,
'AT09001',
'AT09001' );
Thanks
Logged directly into the database as SYS
Use better a dedicated application user.
Anyway if you use a different user that the schema owner of your objects (FLYWAY_USER) you must qualify ALL your references.
especially
VALUES
( ( SELECT Nvl( Max(DEPARTMENT_id), 0) + 1 FROM DEPARTMENT ),
should be
VALUES
( ( SELECT Nvl( Max(DEPARTMENT_id), 0) + 1 FROM FLYWAY_USER.DEPARTMENT ),
SCHEMA 1
I have table transaction table
create table TXN_HEADER
(
txn_id NUMBER(10) not null,
txn_Date date
product_id NUMBER(10),
company_id NUMBER(10),
dealer_id NUMBER(10),
tran_amt number(10,2)
)
The above table having foreign key references to product.product_id and company.company_id.
This table having 5m rows
SCHEMA 2
create table TXN_HEADER_REPORTS
(
txn_id NUMBER(10) not null,
txn_Date date
product_id NUMBER(10),
company_id NUMBER(10),
dealer_id NUMBER(10),
tran_amt number(10,2)
)
here also we have the same constraints , having foreign key references to product.product_id and company.company_id.
in schema 2 we are trying to insert all the rows from schemea 1 to schema 2 in one shot, like this
begin
insert into TXN_HEADER_REPORTS (
txn_id, txn_Date ,product_id,company_id , dealer_id , tran_amt)
select
txn_id, txn_Date ,product_id,company_id , dealer_id , tran_amt
from schema1.TXN_HEADER;
commit;
exception
when others then
< ... procedure to log the errors >
end;
now we are trying to execute the above procedure , and it failed due to foreign key constraint of one rows. But entire my transaction rollback. Actually i dont want to use cursor to process the rows one by one , at it takes long time. So i used to "insert into .. SElect from " but due to constraints of 1 row all my transaction not moved to schema2.txn_Extract_hdr.
Is there any way to trap only that failed and to process the other rows without terminating
Please advice ..
You can create an error log table, and then use a single insert:
exec dbms_errlog.create_error_log(dml_table_name => 'TXN_HEADER_REPORTS');
insert into TXN_HEADER_REPORTS ( txn_id, txn_Date ,product_id,company_id ,
dealer_id , tran_amt)
select txn_id, txn_Date ,product_id,company_id , dealer_id , tran_amt
from schema1.TXN_HEADER
log errors into ERR$_TXN_HEADER_REPORTS reject limit unlimited;
Any rows that can't inserted will be recorded in the ERR table. Note that this is plain SQL, it doesn't need to be in a PL/SQL block.
Read more in the documentation.
I don't understand your constraint.
Does your insert fail because the product_id and company_id don't exists in schema2?
In that case, it may be better to insert the missing company and product records before you insert records into TXN_HEADER_REPORTS of schema2.
insert into company com_sch2
(col1, col2, col2,...)
select col1, col2, col3, ...
from schema1.company com_sch1
where not exists (select 'x'
from company com2
where com2.company_id = com_sch1.company_id);
And the seem for the product table.