oracle sql loader maximum size of a expression - oracle

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

Related

Convert Oracle to Hive - SubQuery can contain only 1 item in Select List

Code and sample data to try on your system:
CREATE TABLE "EMP"
( "DR_SID" NUMBER,
"DR_NAME" VARCHAR2(50 BYTE) COLLATE "USING_NLS_COMP",
"ACTIVE_FLAG" VARCHAR2(1 BYTE) COLLATE "USING_NLS_COMP",
"LAST_UPDATED_TIME" TIMESTAMP (6),
"DATA_SOURCE" VARCHAR2(100 BYTE) COLLATE "USING_NLS_COMP",
"ROW_LIMIT" VARCHAR2(50 BYTE) COLLATE "USING_NLS_COMP",
"VERSION#" NUMBER,
"PARENT_DR_SID" NUMBER
)
;
REM INSERTING into EMP
SET DEFINE OFF;
Insert into EMP (DR_SID,DR_NAME,LAST_UPDATED_TIME,VERSION#,PARENT_DR_SID) values (1,'this should not come1',to_timestamp('18-APR-20 05.05.52.425734000 AM','DD-MON-RR HH.MI.SSXFF AM'),1,1);
Insert into EMP (DR_SID,DR_NAME,LAST_UPDATED_TIME,VERSION#,PARENT_DR_SID) values (2,'come',to_timestamp('19-SEP-20 07.18.56.271199000 AM','DD-MON-RR HH.MI.SSXFF AM'),1,2);
Insert into EMP (DR_SID,DR_NAME,LAST_UPDATED_TIME,VERSION#,PARENT_DR_SID) values (3,'come123',to_timestamp('13-FEB-21 05.05.51.645956000 AM','DD-MON-RR HH.MI.SSXFF AM'),1,3);
Insert into EMP (DR_SID,DR_NAME,LAST_UPDATED_TIME,VERSION#,PARENT_DR_SID) values (4,'come456',to_timestamp('13-FEB-21 05.05.51.951505000 AM','DD-MON-RR HH.MI.SSXFF AM'),1,4);
Insert into EMP (DR_SID,DR_NAME,LAST_UPDATED_TIME,VERSION#,PARENT_DR_SID) values (5,'this should not come2',to_timestamp('18-APR-20 05.05.52.425734000 AM','DD-MON-RR HH.MI.SSXFF AM'),2,1);
Insert into EMP (DR_SID,DR_NAME,LAST_UPDATED_TIME,VERSION#,PARENT_DR_SID) values (6,'this should COME',to_timestamp('18-APR-20 05.05.52.425734000 AM','DD-MON-RR HH.MI.SSXFF AM'),3,1);
SELECT DR_SID, DR_NAME, LAST_UPDATED_TIME, VERSION#, PARENT_DR_SID FROM emp ;
the below query needs to be converted into Hive, can someone help?
SELECT DR_SID, DR_NAME, LAST_UPDATED_TIME, VERSION#, PARENT_DR_SID FROM emp t
where (version#,parent_dr_sid)
in (select max(version#),parent_dr_sid from emp group by parent_dr_sid)
;
I am try to find out which record is latest, so am using version# column (if
version# column has the max value then the record is latest and its previous records are old and not to display).
Now how the records are linked with each other, so we have two columns, dr_sid is pk and parent_dr_sid contains same value to show this record is linked with which old record.
you can see the example here, in the given sample code, dr_sid = 1 is present 3 times in parent_dr_sid, all these 3 records
of parent_dr_sid have the same value as 1 (which is linked to dr_sid).
Now I want the below o/p, can you do the same in hive?
FYI - we cant update the table so trying to update the record in this way and fetching in this way.
DR_SID, DR_NAME, LAST_UPDATED_TIME, VERSION#, PARENT_DR_SID
1 this should not come1 18-APR-20 05.05.52.425734000 AM 1 1
2 come 19-SEP-20 07.18.56.271199000 AM 1 2
3 come123 13-FEB-21 05.05.51.645956000 AM 1 3
4 come456 13-FEB-21 05.05.51.951505000 AM 1 4
5 this should not come2 18-APR-20 05.05.52.425734000 AM 2 1
6 this should COME 18-APR-20 05.05.52.425734000 AM 3 1
Use left semi join to emulate in semantics for tuples.
with input as (
select inline(array(
(1,1),
(1,2),
(2,1),
(2, 2)
)) as (c1, c2)
)
, flt as (
select inline(array(
(1,1),
(2, 2)
)) as (f1, f2)
)
select *, split(version(), ' ')[0] as v
from input
left semi join flt
on input.c1 = flt.f1
and input.c2 = flt.f2
input.c1
input.c2
v
1
1
3.1.3000.7.1.7.0-551
2
2
3.1.3000.7.1.7.0-551
I don't know Hive so these might well be completely useless suggestions; however, see if it helps.
If you can use a subquery in FROM clause, you might do the following:
select e.*
from emp e join (select max(a.create_tm) create_tm, a.open_dt
from emp a group by a.open_dt
) x
on x.create_tm = e.create_tm
and x.open_dt = e.open_dt;
Or, make your subquery return a single column by concatenating values. They look like "time" and "date" (I don't know their datatypes so you might need to apply e.g. TO_CHAR function to these columns; no problem in that, as long as it returns desired result):
select *
from emp
where concat(create_tm, open_dt) in (select concat(max(create_tm), open_dt)
from emp
group by open_dt);
this is working:
SELECT DR_SID, DR_NAME, LAST_UPDATED_TIME, VERSION#--, PARENT_DR_SID
FROM emp t join
(select max(version#) v,parent_dr_sid from emp group by parent_dr_sid) t2
on t.version#=t2.v and t.parent_dr_sid = t2.parent_dr_sid
;

Oracle Query to update substring of column value

We have 2 tables as shown below:
Table A:
ROWNUM
description
1
{"to": "+1111", "from": "9999"}
2
{"to": "+5555", "from": "8888"}
Table B:
COL1
COL2
+1111
222
+5555
666
Please help me with an Oracle query which replaces part of the description column present in Table A from above table.
The numbers present after text "to:" i.e., +1111 and +5555 of Table A (description column)should be compared with COL1 of Table B and replace with corresponding COL2 value.
For example : replace +1111 with 222 in Table A
replace +5555 with 666 in Table A
Table A should look like this post running of the query.
Table A:
ROWNUM
description
1
{"to": "222", "from": "9999"}
2
{"to": "666", "from": "8888"}
Thanks in advance :)
You can use techniques dedicated to JSON within a PL/SQL code values such as
DECLARE
v_jsoncol tableA.description%TYPE;
v_json_obj json_object_t;
v_new_jsoncol tableA.description%TYPE;
v_col1 tableB.col1%TYPE;
v_col2 VARCHAR2(25);
l_key_list json_key_list;
BEGIN
FOR c IN
(
SELECT *
FROM tableA
)
LOOP
v_json_obj := TREAT(json_element_t.parse(c.description) AS json_object_t);
l_key_list := v_json_obj.get_keys;
FOR i IN 1 .. l_key_list.COUNT
LOOP
IF l_key_list (i) = 'to' THEN
v_col1 := v_json_obj.get_string (l_key_list (i));
SELECT TO_CHAR(col2)
INTO v_col2
FROM tableB
WHERE col1 = v_col1;
v_json_obj.put(l_key_list (i),v_col2);
v_new_jsoncol := v_json_obj.to_string;
UPDATE tableA SET description = v_new_jsoncol WHERE row_num = c.row_num;
END IF;
END LOOP;
END LOOP;
END;
/
Demo
I used instr to get 3rd and 4th " chars position to get the value inside and replace it with other query .
Note : ROWNUM , description is reserved keywords, so i advise not to use them as column names
here is the final code:
SELECT ROWNUM ,
REPLACE (description ,
SUBSTR( description , INSTR(description, '"', 1, 3)+1,
INSTR(description, '"', 1, 4) - INSTR(description, '"', 1, 3)-1) ,
(select COL2 from tblB where COL1 =
SUBSTR( description , INSTR(description, '"', 1, 3)+1,
INSTR(description, '"', 1, 4) - INSTR(description, '"', 1, 3)-1)
)
)
from tblA
Don't use string functions for this. You should use JSON functions and can use JSON_MERGEPATCH:
MERGE INTO table_a dst
USING (
SELECT a.ROWID AS rid,
b.col2
FROM table_a a
INNER JOIN table_b b
ON JSON_VALUE(a.description, '$.to' RETURNING VARCHAR2(10)) = b.col1
) src
ON (dst.ROWID = src.RID)
WHEN MATCHED THEN
UPDATE
SET description = JSON_MERGEPATCH(
dst.description,
JSON_OBJECT(KEY 'to' VALUE src.col2)
);
Which, for your sample data:
CREATE TABLE Table_A (description CLOB CHECK (description IS JSON));
INSERT INTO table_a (description)
SELECT '{"to": "+1111", "from": "9999"}' FROM DUAL UNION ALL
SELECT '{"to": "+5555", "from": "8888"}' FROM DUAL;
CREATE TABLE Table_B (COL1, COL2) AS
SELECT '+1111', 222 FROM DUAL UNION ALL
SELECT '+5555', 666 FROM DUAL;
Then:
SELECT * FROM table_a;
Outputs:
DESCRIPTION
{"to":222,"from":"9999"}
{"to":666,"from":"8888"}
db<>fiddle here

How to use multiple conditions in sql loader?

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
)

how to get exact string value from delimited column value match in oracle database

I have 2 tables
Table 1:
#######
ID Location
1 India
2 Australia
Table 2:
############
Name Locations
test1 India|North America
test2 Indiana|Australia
I used the below query to get the Name from table 2 if it contains Location in Locations of table 2.
select Name
from table2 t2 inner join table1 t1
on instr(t1.Location,t2.Locations,length(t1.Location)) >= 1;
But when executed it still gives me results for Indiana as well whereas it should just return me result for location India alone.
I tried using contains in query too, but contains takes second parameter as string but not as column name.
Is there any other approach on this?
regexps always help in such cases
with
table1 (id, location) as (
select 1, 'India' from dual union
select 2, 'Australia' from dual
),
table2 (name, locations) as (
select 'test1', 'India|North America' from dual union
select 'test2', 'Indiana|Australia' from dual
)
select *
from table2 join table1 on
regexp_like (locations, '(^|\|)' || location || '(\||$)')
Try to look up location with delimiter, like this:
select Name from table2 t2
inner join table1 t1 on instr(t2.Locations,t1.Location||'|') >= 1

To split delimited value in column input in where clause

I need to split a column which is Pipe delimited and compare with records. Something like this
select 1
from T1 t1
where t1.date_col not between '01-JAN-2005' and '31-JAN-2005';
I need to fill the between clause value from reference table where the data is something like
ref_table
col_1
01-JAN-2005 | 31-JAN-2005
Query I am trying to achieve
REGEXP_SUBSTR ( col_1
, '^[^|]+') from ref_table
Which is resulting into 01-JAN-2005.
Table T1
date_col
01-Jan-05
15-Jan-05
31-Mar-05
Ref_table
col_1
01-JAN-2005 | 31-JAN-2005
You can do as this:
--Sample data
with t1 as (
select '01-Jan-05' col_1 union
select '15-Jan-05' union
select '31-Mar-05'
),
Ref_table as (
select '01-JAN-2005 | 31-JAN-2005' col_1
)
select *
from t1,
Ref_table r
where to_date(t1.col_1, 'DD/MON/YY')
not between to_date(trim(regexp_replace(r.col_1, '(.*)\|.*', '\1')), 'DD/MON/YY')
and to_date(trim(regexp_replace(r.col_1, '.*\|(.*)', '\1')), 'DD/MON/YY')
Although you really should improve your ref_table design. Store values with some char separated always turns out to be a problem.
Join the dates from table t1 with the intervals from the reference table and subtract the result from the original set of dates:
select t11.date_col
from t1 t11
minus
select t12.date_col
from t1 t12
join (
select to_date ( trim ( substr(col_1, 1, instr(col_1, '|') - 1) ), 'DD-Mon-YYYY' ) d_from
, to_date ( trim ( substr(col_1, instr(col_1, '|') + 1) ), 'DD-Mon-YYYY' ) d_to
from ref_table
) rt on (
rt.d_from <= t12.date_col
AND rt.d_to >= t12.date_col
)
;
I assume that col_1 from your reference table contains the excluded intervals in pairs.

Resources