All technological notes.
SQL*Loader
scp emp.csv oracle@test.com:/home/oracle/sqlloader/emp.csv
-- drop tb if exists
DROP TABLE EMP_LOAD;
-- create tb
CREATE TABLE EMP_LOAD
(EMPNO NUMBER ,
FNAME VARCHAR2(100),
LNAME VARCHAR2(100)
);
-- query before load
SELECT * FROM EMP_LOAD;
emp.ctl# create a new file
touch /home/oracle/sqlloader/emp.ctl
# edit control file
vi /home/oracle/sqlloader/emp.ctl
# Load Data
# INFILE '/home/oracle/sqlloader/emp.csv'
# APPEND
# INTO Table emp_load
# FIELDS TERMINATED BY ','
# (
# empno,
# fname,
# lname
# )
# load data
sqlldr control=/home/oracle/sqlloader/emp.ctl log=/home/oracle/sqlloader/emp.log


SELECT * FROM EMP_LOAD;
truncate table EMP_LOAD;
vi /home/oracle/sqlloader/emp.csv

sqlldr control=/home/oracle/sqlloader/emp.ctl log=/home/oracle/sqlloader/emp.log


Discard File:
discard file is created only when it is needed, and only if you have specified that a discard file should be enabled.The discard file contains records that were filtered out of the load because they did not match any record-selection criteria specified in the control file.
discard file contains record filtered out of the load, the contents of the discard file are records that were not inserted into any table in thedatabase.
discard file.Bad File
sqlplus hr@orclpdb
show user;
show con_name;
-- create tb
DROP TABLE EMP_LOAD;
CREATE TABLE EMP_LOAD
(
EMPNO NUMBER ,
FNAME VARCHAR2(100),
LNAME VARCHAR2(100)
);
SELECT * FROM EMP_LOAD;
-- return none
# create dir for lab to place csv
mkdir /home/oracle/sqlloader/discard_file
# copy the emp.csv file to this dir
touch /home/oracle/sqlloader/discard_file/emp.ctl
vi /home/oracle/sqlloader/discard_file/emp.ctl
# note: we will not load empno='1008'
# using when clause to filter
Load Data
INFILE '/home/oracle/sqlloader/discard_file/emp.csv'
APPEND
INTO Table emp_load
WHEN empno <> '1008'
FIELDS TERMINATED BY ','
(
empno,
fname,
lname
)
sqlldr control=/home/oracle/sqlloader/discard_file/emp.ctl log=/home/oracle/sqlloader/discard_file/emp.log


- this example shows both error and filter
- this did not generate the discard file due to ignorance of the option.
sqlplus hr@orclpdb
SELECT count(*) FROM EMP_LOAD;
-- 16120
truncate table EMP_LOAD;
sqlldr control=/home/oracle/sqlloader/discard_file/emp.ctl log=/home/oracle/sqlloader/discard_file/emp.log DISCARD=emp.dsc


SQL*Loader can load data by using either a convention path load, or a direct path load.
conventional path load:
INSERT statements to populate tables in Oracle Database.direct path load:
data blocks, and then writing the data blocks directly to the database files.direct load does not compete with other users for database resources, so it can usually load data at near disk speed.SQL*Loader never creates tables.
tables that you want to be loaded must already exist in the database.INSERT privileges on the table to be loaded.DELETE privileges on the table that you want to be loaded, when using the REPLACE or TRUNCATE option to empty old data from the table before loading the new data in its place.redo entriesINSERT triggersCOMMIT
COMMIT operation.
show user;
--USER is "HR"
show con_name;
--CON_NAME
--------------------------------
--ORCLPDB
drop table emp_x;
drop table dept_x;
-- create tb with constraint
create table dept_x
(
deptno number,
dname varchar2(100),
constraint dept_x primary key (deptno)
);
insert into dept_x values (1, 'sales');
commit;
select * from dept_x;
-- 1 sales
-- create tb with constraints, including fk
create table emp_x
(
empid number,
name varchar2(10) not null,
gender varchar(1),
deptno number,
address varchar2(100),
constraint emp_x_pk primary key (empid),
constraint emp_x_uk1 unique (name),
constraint emp_x_fk1 foreign key (deptno) references dept_x(deptno),
constraint emp_x_chq1 check ( gender in ('M','F') )
);
select * from emp_x;
-- return none
select * from user_constraints
where table_name='EMP_X';

Note: In this scenario, all data in the csv file match the DDL of the tb, exspecially the deptno is 1, matching the data in dept table.
Create dir and place csv file
# create dir to place EMPLOYEES.csv
mkdir /home/oracle/sqlloader/con_load
touch /home/oracle/sqlloader/con_load/EMPLOYEES.ctl
vi /home/oracle/sqlloader/con_load/EMPLOYEES.ctl
# Load Data
# INFILE '/home/oracle/sqlloader/con_load/EMPLOYEES.csv'
# APPEND
# INTO Table emp_x
# FIELDS TERMINATED BY ','
# (
# empid,
# name,
# gender,
# deptno,
# address
# )
sqlldr control=/home/oracle/sqlloader/con_load/EMPLOYEES.ctl log=/home/oracle/sqlloader/con_load/EMPLOYEES.log

- It shows every 250 records, oracle commits the records.


select count(*) from emp_x;
--300
-- truncate tb
truncate table emp_x
vi /home/oracle/sqlloader/con_load/EMPLOYEES.csv
# 257,khaledalkhudari,M,1,NA
# 258,KH258,x,1,NA
# 259,KH259,M,2,NA

sqlldr control=/home/oracle/sqlloader/con_load/EMPLOYEES.ctl log=/home/oracle/sqlloader/con_load/EMPLOYEES.log

- only 297 rows imported.


- This shows that when importing with conventional path load, oracle checks constraints.
-- truncate tb
truncate table emp_x
vi /home/oracle/sqlloader/con_load/EMPLOYEES.csv
# keep the change in the previous test
# 260,,M,1,NA

sqlldr control=/home/oracle/sqlloader/con_load/EMPLOYEES.ctl log=/home/oracle/sqlloader/con_load/EMPLOYEES.log



- load check the not null constraint.
-- truncate tb
truncate table emp_x;
vi /home/oracle/sqlloader/con_load/EMPLOYEES.csv
# keep the change in the previous tests
# make the id 280 = 1

sqlldr control=/home/oracle/sqlloader/con_load/EMPLOYEES.ctl log=/home/oracle/sqlloader/con_load/EMPLOYEES.log



truncate table emp_x;
# instruct loader to commit each 50 records.
sqlldr control=/home/oracle/sqlloader/con_load/EMPLOYEES.ctl log=/home/oracle/sqlloader/con_load/EMPLOYEES.log ROWS=50

data saves (faster operation)
redo only under specific conditionsPRIMARY KEY, UNIQUE, and NOT NULLINSERT triggersDIRECT=TRUE clauseshow user;
-- USER is "HR"
show con_name;
--CON_NAME
--------------------------------
--ORCLPDB
drop table emp_x;
drop table dept_x;
-- create tb with pk
create table dept_x
(deptno number,
dname varchar2(100),
constraint dept_x primary key (deptno)
);
insert into dept_x values (1, 'sales');
commit;
select * from dept_x;
-- 1 sales
-- create tb with constraints
create table emp_x
(
empid number,
name varchar2(10) not null,
gender varchar(1),
deptno number,
address varchar2(100),
constraint emp_x_pk primary key (empid),
constraint emp_x_uk1 unique (name),
constraint emp_x_fk1 foreign key (deptno) references dept_x(deptno),
constraint emp_x_chq1 check ( gender in ('M','F') )
);
select * from emp_x;
-- return none
mkdir /home/oracle/sqlloader/direct_load
# place EMPLOYEES.csv in this dir
touch /home/oracle/sqlloader/direct_load/EMPLOYEES.ctl
vi /home/oracle/sqlloader/direct_load/EMPLOYEES.ctl
Load Data
INFILE '/home/oracle/sqlloader/direct_load/EMPLOYEES.csv'
APPEND
INTO Table emp_x
FIELDS TERMINATED BY ','
(
empid,
name,
gender,
deptno,
address
)
# using DIRECT=TRUE clause
sqlldr control=/home/oracle/sqlloader/direct_load/EMPLOYEES.ctl log=/home/oracle/sqlloader/direct_load/EMPLOYEES.log DIRECT=TRUE


select count(*) from emp_x;
-- 300

select * from user_constraints
where table_name='EMP_X';

- only the not null, unique and pk constraints are enabled after loading.
ALTER TABLE emp_x ENABLE CONSTRAINT EMP_X_CHQ1;
ALTER TABLE emp_x ENABLE CONSTRAINT EMP_X_FK1;
-- verify
select * from user_constraints
where table_name='EMP_X';

select * from user_indexes
where table_name='EMP_X';
-- the status is valid
truncate table emp_x;
vi /home/oracle/sqlloader/direct_load/EMPLOYEES.csv
# 287,KH287,x,1,NA
# 288,KH288,M,2,NA

# using DIRECT=TRUE clause
sqlldr control=/home/oracle/sqlloader/direct_load/EMPLOYEES.ctl log=/home/oracle/sqlloader/direct_load/EMPLOYEES.log DIRECT=TRUE

- all data are loaded without any issues because direct path load disables the check and fk constraints.
select constraint_name, constraint_type, search_condition, status
from user_constraints
where table_name='EMP_X';
--SYS_C007811 C "NAME" IS NOT NULL ENABLED
--EMP_X_PK P ENABLED
--EMP_X_UK1 U ENABLED
--EMP_X_FK1 R DISABLED
--EMP_X_CHQ1 C gender in ('M','F') DISABLED
ALTER TABLE emp_x ENABLE CONSTRAINT EMP_X_CHQ1;
--Error starting at line : 110 in command -
--ALTER TABLE emp_x ENABLE CONSTRAINT EMP_X_CHQ1
--Error report -
--ORA-02293: cannot validate (HR.EMP_X_CHQ1) - check constraint violated
--02293. 00000 - "cannot validate (%s.%s) - check constraint violated"
--*Cause: an alter table operation tried to validate a check constraint to
-- populated table that had nocomplying values.
--*Action: Obvious
ALTER TABLE emp_x ENABLE CONSTRAINT EMP_X_FK1;
--Error starting at line : 120 in command -
--ALTER TABLE emp_x ENABLE CONSTRAINT EMP_X_FK1
--Error report -
--ORA-02298: cannot validate (HR.EMP_X_FK1) - parent keys not found
--02298. 00000 - "cannot validate (%s.%s) - parent keys not found"
--*Cause: an alter table validating constraint failed because the table has
-- child records.
--*Action: Obvious
PK and Unique, Oracle will disalbe the constraint and insert data.
not null, Oracle will reject and put it in a bad file.
not null constraint.log file, all PK, Not Null, and unique constraints will display.bad file/rejected data, only the not null records can be found.-- truncate tb
truncate table emp_x;
-- enable constraints
ALTER TABLE emp_x ENABLE CONSTRAINT EMP_X_CHQ1;
ALTER TABLE emp_x ENABLE CONSTRAINT EMP_X_FK1;
vi /home/oracle/sqlloader/direct_load/EMPLOYEES.csv
# MAKE THE ID 289=1
# 290,,M,1,NA
# 291,KH1,M,1,NA

# using DIRECT=TRUE clause
sqlldr control=/home/oracle/sqlloader/direct_load/EMPLOYEES.ctl log=/home/oracle/sqlloader/direct_load/EMPLOYEES.log DIRECT=TRUE

- one record was rejected.

- the rejected record in bad file is the one violating the not null constraint.

- When violating the PK and unique constraints, Oracle disable them but insert the record.
- When violating the not null constraint, Oracle reject the record.
-- query constraints
select constraint_name, constraint_type, search_condition, status
from user_constraints
where table_name='EMP_X';
--SYS_C007811 C "NAME" IS NOT NULL ENABLED
--EMP_X_FK1 R DISABLED
--EMP_X_CHQ1 C gender in ('M','F') DISABLED
--EMP_X_PK P DISABLED
--EMP_X_UK1 U DISABLED
SELECT * FROM emp_x
ORDER BY 1;
-- note 2 record with pk equal to 1
--1 KH289 M 1 "NA"
--1 KH1 M 1 "NA"
SELECT * FROM emp_x
ORDER BY 2;
-- note 2 records with the same name
--1 KH1 M 1 "NA"
--291 KH1 M 1 "NA"
SQL*Loader express mode
In express mode, a SQL*Loader control file is not used. I
ALL_TAB_COLUMNS view to determine the input field order and data types.The main benefit:
control file.
external tables using parallel inserts with the append hint.append hint on an insert statement tells the database to use direct path for loading table data.
show user;
--USER is "HR"
show con_name;
--CON_NAME
--------------------------------
--ORCLPDB
drop table emp_x;
drop table dept_x;
-- create tb with pk
create table dept_x
(
deptno number,
dname varchar2(100),
constraint dept_x primary key (deptno)
);
insert into dept_x values (1, 'sales');
commit;
select * from dept_x;
-- 1 sales
create table emp_x
(
empid number,
name varchar2(10) not null,
gender varchar(1),
deptno number,
address varchar2(100),
constraint emp_x_pk primary key (empid),
constraint emp_x_uk1 unique (name),
constraint emp_x_fk1 foreign key (deptno) references dept_x(deptno),
constraint emp_x_chq1 check ( gender in ('M','F') )
);
select * from emp_x;
-- return none
mkdir /home/oracle/sqlloader/express_mode
# place dat file
- The csv file needs to change the extention with .dat.
cd /home/oracle/sqlloader/express_mode
sqlldr hr@orclpdb TABLE=emp_x
- SQL*Loader first created a temporary
external table, used theexternal tableto load the content of the external data file into the table, and finally dropped the temporaryexternal table.- The command will generate the log file and
.log_xtfile




select count(*) from emp_x;
-- 300
-- existing data
delete from emp_x;
commit;
sqlldr hr@orclpdb TABLE=emp_x DIRECT=NO

sqlldr hr@orclpdb TABLE=emp_x DIRECT=YES

Loader uses direct path the constraints are disabled all valid rows are inserted.
SELECT count(*) FROM emp_x
ORDER BY 1;
-- 598
select constraint_type, status
from user_constraints
where table_name='EMP_X';
--C ENABLED
--R DISABLED
--C DISABLED
--P DISABLED
--U DISABLED
delete from emp_x;
commit;
vi /home/oracle/sqlloader/express_mode/emp_x.dat
# 1,KH280,M,1,NA
sqlldr hr@orclpdb TABLE=emp_x


If any of the constraint has been violated, Oracle will not continue the loading.
vi /home/oracle/sqlloader/express_mode/emp_x.dat
# 280,KH1,M,1,NA
sqlldr hr@orclpdb TABLE=emp_x


If any of the constraint has been violated, Oracle will not continue the loading.
-- existing data
delete from emp_x;
commit;
vi /home/oracle/sqlloader/express_mode/emp_x.dat
# 280,KH28888888888888888888888888888,M,1,NA
sqlldr hr@orclpdb TABLE=emp_x


If a row violate the length of a colum, this row will not insert. A bad file will be created.
select count(*)
from emp_x;
-- 299
####