How to use multiple conditions in sql loader? - oracle

I have one csv file with below format.First column is id second column is name and third column is dept. There are more than 700k rows in this file. I was trying to move only department 10, 90, 30 and 70 details in a oracle table by using SQL Loader.
100,AAA,10
101,BBB,10
102,CCC,20
103,DDD,30
104,EEE,40
105,FFF,50
106,GGG,70
107,HHH,60
108,III,20
109,JJJ,80
110,KKK,90
111,LLL,90
112,MMM,50
113,NNN,80
114,OOO,10
My table format is:-
create table DEPT_LOADER(
ID NUMBER
,NAME VARCHAR2(100)
,DEPT number
);
and below is the control file
load data
infile 'F:\SQL_Loader\dept.csv'
badfile 'F:\SQL_Loader\dept.bad'
discardfile 'F:\SQL_Loader\dept.dsc'
insert
into table DEPT_LOADER
when dept = '10' or dept = '90' or dept = '30' or dept = '70'
fields terminated by ','
(id,name,dept)
but oracle didn't allow "or" operator in when clause. I tried with "in" clause and getting same type of error.
SQL*Loader-350: Syntax error at line 7.
Expecting "(", found "or".
when dept = '10' or dept = '90' or dept = '30' or dept = '70'
Please help me on that. how can i use more than one condition in control file

SQL*Loader does not allow OR operator in WHEN clauses. You should use multiple INSERT INTO DEPT_LOADER .
Your control file should be like;
LOAD DATA
INFILE 'F:\SQL_Loader\dept.csv'
BADFILE 'F:\SQL_Loader\dept.bad'
DISCARDFILE 'F:\SQL_Loader\dept.dsc'
INSERT
INTO TABLE DEPT_LOADER WHEN DEPT = '10'
FIELDS TERMINATED BY ','
(
ID POSITION(1),
NAME,
DEPT
)
INTO TABLE DEPT_LOADER WHEN DEPT = '90'
FIELDS TERMINATED BY ','
(
ID POSITION(1),
NAME,
DEPT
)
INTO TABLE DEPT_LOADER WHEN DEPT = '30'
FIELDS TERMINATED BY ','
(
ID POSITION(1),
NAME,
DEPT
)
INTO TABLE DEPT_LOADER WHEN DEPT = '70'
FIELDS TERMINATED BY ','
(
ID POSITION(1),
NAME,
DEPT
)

Related

How to read field with comma through Oracle external table

I have a position separated text file which I have to read through Oracle external tables. In that position separated file I field as name separated by comma. For example:
123 abc,def 456. So I have to insert data into 3 columns. Fisrt column would have 123, second column would have abc,def and third column would have 456. In access parameter I have given "records delimited by newline". But while selecting data from external table, it only gives data before comma (abc). But I want to read abc,def. Can anybody help me with this?
The following works for me;
CREATE TABLE test
(
col_1 NUMBER,
col_2 VARCHAR2(30),
col_3 NUMBER
)
ORGANIZATION EXTERNAL
( TYPE ORACLE_LOADER
DEFAULT DIRECTORY MY_DIR
ACCESS PARAMETERS
( RECORDS DELIMITED BY '\r\n'
FIELDS TERMINATED BY ' '
OPTIONALLY ENCLOSED BY '"'
MISSING FIELD VALUES ARE NULL
( col_1, col_2, col_3
)
)
LOCATION (MY_DIR:'test.txt')
)
REJECT LIMIT UNLIMITED;
Bear in mind that "records delimited by '/r/n'" may be specific to Windows but my results are as below;
SQL> select * from test
2 /
COL_1 COL_2 COL_3
---------- ------------------------------ ----------
123 ABC,DEF 123
789 ABCD,EF 123
456 A,B,C,DEF 123

Missing right parenthesis while import data from flat files to table

I have load data infile .... one flat file. I want to load the data into table tab from this flat file. I want to pass few values like 'ab', 'cd', 'ef' in column col6 of the table. When i write the code in the flat file like this
load data infile <source-path>
into tab
fields terminated by ','
(
col1 "TRIM(:col1)" ,
............
...........
col6 "('ab','cd','ef')",
..........)
But when i load this file into the table then i found an error ORA-00907: Missing Right Parenthesis. How to resolve this error so that i can insert value of 'ab', 'cd', 'ef' in col6 of table tab.
You can use a multitable insert, with three inserts into the same table:
load data infile <source-path>
into tab
fields terminated by ','
(
col1 "TRIM(:col1)" ,
............
...........
col6 CONSTANT 'ab',
..........)
into tab
fields terminated by ','
(
col1 POSITION(1) "TRIM(:col1)" ,
............
...........
col6 CONSTANT 'cd',
..........)
into tab
fields terminated by ','
(
col1 POSITION(1) "TRIM(:col1)" ,
............
...........
col6 CONSTANT 'ef',
..........)
The POSITION(1) resets to the start of the record, so it sees the same values from the source record again fir each insert. Read more.
Alternatively you could insert into a staging table, with a single row for each record in your file, and excluding the constant-value col6 completely - which you could with SQL*Loader:
load data infile <source-path>
into staging_tab
fields terminated by ','
(
col1 "TRIM(:col1)" ,
............
...........
col5 ...
col7 ...
..........)
... or as an external table; and then insert into your real table by querying the staging table and cross-joining with a CTE containing the constant values:
insert into tab (col1, col2, ..., col6, ...)
with constants (col6) as (
select 'ab' from dual
union all select 'cd' from dual
union all select 'ef' from dual
)
select st.col1, st.col2, ..., c.col6, ...
from staging_tab st
cross join constants c;
For each row in the staging table you'll get three rows in the real table, one for each of the dummy rows in the CTE. You could do the same with with a collection instead of a CTE:
insert into tab (col1, col2, col6)
select st.col1, st.col2, c.column_value
from staging_tab st
cross join table(sys.odcivarchar2list('ab', 'cd', 'ef')) c;
This time you get one row for each element in the collection - which is expanded into multiple rows by the table collection clause. The result is the same.

Why does full outer join in HIVE gives weird result when one of the join fields is missing?

I'm comparing the behavior between SQL engines. Oracle has the behavior I would expect from a SQL engine for full outer joins:
Oracle
CREATE TABLE sql_test_a
(
ID VARCHAR2(4000 BYTE),
FIRST_NAME VARCHAR2(200 BYTE),
LAST_NAME VARCHAR2(200 BYTE)
);
CREATE TABLE sql_test_b
(
NUM VARCHAR2(4000 BYTE),
FIRST_NAME VARCHAR2(200 BYTE),
LAST_NAME VARCHAR2(200 BYTE)
);
INSERT INTO sql_test_a (ID, FIRST_NAME, LAST_NAME) VALUES ('1', 'John', 'Snow');
INSERT INTO sql_test_a (ID, FIRST_NAME, LAST_NAME) VALUES ('2', 'Mike', 'Tyson');
INSERT INTO sql_test_b (NUM, FIRST_NAME, LAST_NAME) VALUES ('20', 'Mike', 'Tyson');
When I execute the following, it gives me the expected result. The resulting table contains two rows, with one of the rows containing NULL for the NUM field, because there is no john snow in the table sql_test_b.
SELECT A.FIRST_NAME, A.LAST_NAME, A.ID, B.NUM
FROM
SQL_TEST_A A
FULL OUTER JOIN
SQL_TEST_B B
ON
A.FIRST_NAME = B.FIRST_NAME
AND
A.LAST_NAME = B.LAST_NAME;
You can test the sql script here: http://sqltest.net/
HIVE
In HIVE, however, if you were to try the same thing, the full outer join results in a table with two rows. The row that should be the "John Snow" row contains NULL for the fields FIRST_NAME, LAST_NAME, and NUM. The 1 is filled in for ID, but that's it.
Why such weird behavior in HIVE? Is this a bug? Or am I missing something...because Oracle 11g seems to handle this much better. Thanks.
I could not simulate the result reported by #Candic3
I used the below statements along with the same "select" query as in the question.
CREATE TABLE IF NOT EXISTS sql_test_a (ID String, FIRST_NAME String, LAST_NAME String) COMMENT 'sql_test_a'
ROW FORMAT DELIMITED
FIELDS TERMINATED BY '\t'
LINES TERMINATED BY '\n'
STORED AS TEXTFILE;
CREATE TABLE IF NOT EXISTS sql_test_b (NUM String, FIRST_NAME String, LAST_NAME String) COMMENT 'sql_test_b'
ROW FORMAT DELIMITED
FIELDS TERMINATED BY '\t'
LINES TERMINATED BY '\n'
STORED AS TEXTFILE;
INSERT INTO sql_test_a VALUES ('1', 'John', 'Snow');
INSERT INTO sql_test_a VALUES ('2', 'Mike', 'Tyson');
INSERT INTO sql_test_b VALUES ('20', 'Mike', 'Tyson');
SELECT A.FIRST_NAME, A.LAST_NAME, A.ID, B.NUM
FROM
SQL_TEST_A A
FULL OUTER JOIN
SQL_TEST_B B
ON
A.FIRST_NAME = B.FIRST_NAME
AND
A.LAST_NAME = B.LAST_NAME;
Please find the result attached.
However, select query would return NULL due to unnoticed minor mistakes like data-type mismatch between the DDL and the actual data (say, from flat files) or mismatch among the delimiter mentioned in the DDL and the ones in the actual data.
I think issue with "(" after on condition which is slightly different than traditional sql.
SELECT A.FIRST_NAME, A.LAST_NAME, A.ID, B.NUM
FROM
SQL_TEST_A A
FULL OUTER JOIN
SQL_TEST_B B ON
(A.FIRST_NAME = B.FIRST_NAME AND A.LAST_NAME = B.LAST_NAME);
In select statement you have used A.FIRST_NAME, A.LAST_NAME which is not present for the row from table B. That is why the null value. Instead use COALESCE to find non null value between A.FIRST_NAME and B.FIRST_NAME
SELECT COALESCE(A.FIRST_NAME, B.FIRST_NAME) as FIRST_NAME, COALESCE(A.LAST_NAME, B.LAST_NAME) as LAST_NAME, A.ID, B.NUM
FROM
SQL_TEST_A A
FULL OUTER JOIN
SQL_TEST_B B
ON
A.FIRST_NAME = B.FIRST_NAME
AND
A.LAST_NAME = B.LAST_NAME;

oracle sql loader maximum size of a expression

I have a ctl file to use sqlldr, but the length of the expression is greater than 258 and is the minimum length that i can get in the query is impossible to me create a query with less characters.
My ctl is:
OPTIONS (PARALLEL=TRUE, SILENT=(HEADER,FEEDBACK), ERRORS=1000000)
LOAD DATA
INFILE 'file.csv'
--BADFILE 'file.bad'
APPEND INTO TABLE table1
FIELDS TERMINATED BY "|"
TRAILING NULLCOLS
(
id_user CONSTANT 2,
number_user ,
FULL_TIMESTAMP date "YYYY-MM-DD HH24:MI:SS",
id_date ,
id_time ,
pn BOUNDFILLER,
service_name EXPRESSION "select service_name from pack_table where service_name in (select service_name from table_2 where id_number in (select id_number from table_3 WHERE id_user=2 and (id_date between to_char(to_date(:id_date,'YYYYMMDD')-1,'YYYYMMDD') and :id_date) and number_user= :number_user))",
bill_response ,
joined CONSTANT 0
)
Oracle say me that the maximum length of a expression is 258 =(
I can not change the name of the colums of the tables.
My idea was use other expression BOUNDFILLER, but it not works for me ='(
OPTIONS (PARALLEL=TRUE, SILENT=(HEADER,FEEDBACK), ERRORS=1000000)
LOAD DATA
INFILE '_INFILE_'
--BADFILE '_INFILE_.bad'
APPEND INTO TABLE table1
FIELDS TERMINATED BY "|"
TRAILING NULLCOLS
(
id_user CONSTANT _MNO_,
number_user ,
FULL_TIMESTAMP date "YYYY-MM-DD HH24:MI:SS",
id_date ,
id_time ,
pn BOUNDFILLER,
ic "select id_number from (select id_number from table_3 WHERE id_user=2 and (id_date between to_char(to_date(:id_date,'YYYYMMDD')-1,'YYYYMMDD') and :id_date) and number_user= :number_user order by id_date asc) where rownum=1" BOUNDFILLER,
service_name EXPRESSION "select service_name from pack_table where service_name in (select service_name from table_2 where id_number = :ic)",
bill_response ,
joined CONSTANT 0
)
i don't know what i can to do.
Who can help me?
Thanks
move the select statement to a function and use select myfunction(params) from dual instead

Hardcode value of column name and column in select query with pipe delimiter

I want to hard-code a column name and its value as New York in a select query with pipe delimiter. E.g. Emp table has columns EmpId, EmpName, Salary. I want output such as
Select EmpId ||'|'||
EmpName ||'|'||
'NewYork' as City ||'|'||
Salary
from Emp
Here I want City column in output query and its value should be 'NewYork' for each record.
Here I am getting error as "FROM keyword not found where expected". When I use comma instead of Pipe Delimiter I am getting result but not with Pipe. Please advise. Thanks in advance.
with emps as (
select 1 as id, 'Smith' as name, 2000 as salary from dual
union
select 2, 'Jones', 2200 from dual
)
select
id || '|' || name as record1,
id || '|' || name || '|NewYork|' || salary as record2,
'NewYork' as city
from emps;

Resources