I get error : 06550. 00000 - "line %s, column %s:\n%s" *Cause: Usually a PL/SQL compilation error - oracle

I am new in oracle . I have three table . I want insert to table tbl_ledger_branch from join tbl_ledger , tbl_ledger_input
my code is :
DECLARE
STARTDATE DATE := MIN (EFF_DATE );
ENDDATE DATE := MAX (EFF_DATE ) ;
i DATE ;
BEGIN
for i in SATARTDATE .. ENDDATE LOOP
insert into tbl_ledger_branch (ledger_code , name , depth , parent_code , balance , ref_cur_id , eff_date , ref_branch , cur_balance , number_date )
select a.ledger_code , max( b.name ) name , max(b.depth) depth , max(CONCAT(SUBSTR(b.LEDGER_CODE,1,9),'00')) PARENT_CODE , sum(a.balance) balance ,
i eff_date , a.ref_branch , a.cur_balance
from tbl_ledger_input a inner join tbl_ledger b
on a.ledger_code = b.ledger_code
where eff_date <= i
group by a.ref_branch ,a.ref_cur_id ,a.ledger_code , a.cur_balance ;
END LOOP ;
END ;
but I get error :
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
please help me .

Based on your data i came up with the below, it is not perfect but atleast you can start with this SQL.
insert into tbl_ledger_branch
(ledger_code,
name,
depth,
parent_code,
balance,
ref_cur_id,
eff_date,
ref_branch,
cur_balance,
number_date)
with dates as
(SELECT max(EFF_DATE) start_date, max(EFF_DATE) end_date
from tbl_ledger_input a)
select a.ledger_code,
max(b.name) name,
max(b.depth) depth,
max(CONCAT(SUBSTR(b.LEDGER_CODE, 1, 9), '00')) PARENT_CODE,
sum(a.balance) balance,
a.ref_cur_id,
a.eff_date,
a.ref_branch,
a.cur_balance,
a.eff_date
from tbl_ledger_input a, tbl_ledger b, dates c
where a.ledger_code = b.ledger_code
AND a.eff_date >= c.start_date
AND a.eff_date <= c.end_date
group by a.ref_branch,
a.ref_cur_id,
a.ledger_code,
a.cur_balance,
a.eff_date;

Related

Insert bulk records in to remote database (dblink) using Bulk Collect

I want to insert huge records from different tables in to a destination remote table 'Audition_Detail' using DBLINK - #FMATLINK. I have used Bulk collect, but its throwing errors. I have gone through some links too:
Overcoming the restriction on bulk inserts over a database link
PLS-00394: Wrong number of values in the INTO list of a fetch statement
The code is as follows:
DECLARE
TYPE FETCH_ARRAY IS TABLE OF AUDITION_DETAIL#FMATLINK%ROWTYPE;
A_DATA FETCH_ARRAY;
CURSOR A_CUR IS
--------------------------------------------------------Address1--------------------------------------------------------------------------
SELECT A.PARTY_SITE_NUMBER FMAT_FMATID, B.ZADDRESSFMATID F4F_FMATID,
C.ADDRESS1 FMAT_VALUE, B.STREET F4F_VALUE , 'ADDRESS1'
FROM APPS.HZ_PARTY_SITES#FMATLINK A , f4f_corporateaccount B , APPS.HZ_LOCATIONS#FMATLINK C
WHERE 1=1
AND B.ROLECODETEXT = 'Site Account'
AND A.PARTY_SITE_NUMBER = B.ZADDRESSFMATID
AND A.STATUS = 'A'
UNION ALL
------------------------------------------------------Address2-----------------------------------------------------------------------------
SELECT A.PARTY_SITE_NUMBER FMAT_FMATID, B.ZADDRESSFMATID F4F_FMATID,
C.ADDRESS2 FMAT_VALUE, B.addressline1 F4F_VALUE , 'ADDRESS2'
FROM APPS.HZ_PARTY_SITES#FMATLINK A , f4f_corporateaccount B , APPS.HZ_LOCATIONS#FMATLINK C
WHERE 1=1
AND B.ROLECODETEXT = 'Site Account'
AND A.PARTY_SITE_NUMBER = B.ZADDRESSFMATID
AND A.STATUS = 'A'
BEGIN
OPEN A_CUR;
LOOP
FETCH A_CUR BULK COLLECT INTO A_DATA LIMIT 20;
FORALL IN 1..A_DATA.COUNT
INSERT INTO AUDITION_DETAIL#FMATLINK VALUES A_DATA(i);
EXIT WHEN A_CUR%NOTFOUND;
END LOOP;
CLOSE A_CUR;
COMMIT;
END;
Error report -
ORA-06550: line 39, column 3:
PLS-00394: wrong number of values in the INTO list of a FETCH
statement
ORA-06550: line 39, column 3:
PL/SQL: SQL Statement ignored
ORA-06550: line 40, column 4:
PLS-00739: FORALL INSERT/UPDATE/DELETE not supported on remote tables
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
The error message seems clear enough :
FORALL INSERT/UPDATE/DELETE not supported on remote tables.
Indeed you link to another question which explains that this is an implementation restriction. PL/SQL does not allow us to use FORALL statements across database links and that is that.
Fortunately you don't need to use bulk collect and FORALL in your code. A simple INSERT INTO .... SELECT statement should see you right:
INSERT INTO AUDITION_DETAIL#FMATLINK
SELECT A.PARTY_SITE_NUMBER FMAT_FMATID, B.ZADDRESSFMATID F4F_FMATID,
C.ADDRESS1 FMAT_VALUE, B.STREET F4F_VALUE , 'ADDRESS1'
FROM APPS.HZ_PARTY_SITES#FMATLINK A , f4f_corporateaccount B , APPS.HZ_LOCATIONS#FMATLINK C
WHERE 1=1
AND B.ROLECODETEXT = 'Site Account'
AND A.PARTY_SITE_NUMBER = B.ZADDRESSFMATID
AND A.STATUS = 'A'
UNION ALL
------------------------------------------------------Address2-----------------------------------------------------------------------------
SELECT A.PARTY_SITE_NUMBER FMAT_FMATID, B.ZADDRESSFMATID F4F_FMATID,
C.ADDRESS2 FMAT_VALUE, B.addressline1 F4F_VALUE , 'ADDRESS2'
FROM APPS.HZ_PARTY_SITES#FMATLINK A , f4f_corporateaccount B , APPS.HZ_LOCATIONS#FMATLINK C
WHERE 1=1
AND B.ROLECODETEXT = 'Site Account'
AND A.PARTY_SITE_NUMBER = B.ZADDRESSFMATID
AND A.STATUS = 'A'
Your code doesn't use the explicit ANSI 92 join syntax and you have scrunched up the code so it's hard to read. Consequently it is easy to miss that you haven't written a join condition for APPS.HZ_LOCATIONS#FMATLINK C. So both subqueries will produce a Cartesian Product for all records in C. You probably don't want this.
SELECT A.PARTY_SITE_NUMBER as FMAT_FMATID
, B.ZADDRESSFMATID as F4F_FMATID
, C.ADDRESS2 as FMAT_VALUE
, B.addressline1 as F4F_VALUE
, 'ADDRESS2'
FROM APPS.HZ_PARTY_SITES#FMATLINK A
inner join f4f_corporateaccount B on A.PARTY_SITE_NUMBER = B.ZADDRESSFMATID
inner join APPS.HZ_LOCATIONS#FMATLINK C on ** something goes here **
WHERE B.ROLECODETEXT = 'Site Account'
AND A.STATUS = 'A'
Easier to understand, easy to spot the missing join. Readability is a feature.

Ora-00932 - expected NUMBER got -

I have been running the below query without issue:
with Nums (NN) as
(
select 0 as NN
from dual
union all
select NN+1 -- (1)
from Nums
where NN < 30
)
select null as errormsg, trunc(sysdate)-NN as the_date, count(id) as the_count
from Nums
left join
(
SELECT c1.id, trunc(c1.c_date) as c_date
FROM table1 c1
where c1.c_date > trunc(sysdate) - 30
UNION
SELECT c2.id, trunc(c2.c_date)
FROM table2 c2
where c2.c_date > trunc(sysdate) -30
) x1
on x1.c_date = trunc(sysdate)-Nums.NN
group by trunc(sysdate)-Nums.NN
However, when I try to pop this in a proc for SSRS use:
procedure pr_do_the_thing (RefCur out sys_refcursor)
is
oops varchar2(100);
begin
open RefCur for
-- see above query --
;
end pr_do_the_thing;
I get
Error(): PL/SQL: ORA-00932: inconsistent datatypes: expected NUMBER got -
Any thoughts? Like I said above, as a query, there is no issue. As a proc, the error appears at note (1) int eh query.
This seems to be bug 18139621 (see MOS Doc ID 2003626.1). There is a patch available, but if this is the only place you encounter this, it might be simpler to switch to a hierarchical query:
with Nums (NN) as
(
select level - 1
from dual
connect by level <= 31
)
...
You could also calculate the dates inside the CTE (which also fails with a recursive CTE):
with Dates (DD) as
(
select trunc(sysdate) - level + 1
from dual
connect by level <= 31
)
select null as errormsg, DD as the_date, count(id) as the_count
from Dates
left join
(
SELECT c1.id, trunc(c1.c_date) as c_date
FROM table1 c1
where c1.c_date > trunc(sysdate) - 30
UNION
SELECT c2.id, trunc(c2.c_date)
FROM table2 c2
where c2.c_date > trunc(sysdate) -30
) x1
on x1.c_date = DD
group by DD;
I'd probably organise it slightly differently, so the subquery doesn't limit the date range directly:
with dates (dd) as
(
select trunc(sysdate) - level + 1
from dual
connect by level <= 31
)
select errormsg, the_date, count(id) as the_count
from (
select null as errormsg, d.dd as the_date, c1.id
from dates d
left join table1 c1 on c1.c_date >= d.dd and c1.c_date < d.dd + 1
union all
select null as errormsg, d.dd as the_date, c2.id
from dates d
left join table2 c2 on c2.c_date >= d.dd and c2.c_date < d.dd + 1
)
group by errormsg, the_date;
but as always with these things, check the performance of each approach...
Also notice that I've switched from union to union all. If an ID could appear more than once on the same day, in the same table or across both tables, then the counts will be different - you need to decide whether you want to count them once or as many times as they appear. That applies to your original query too.

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

How to insert duplicate record in the same table with only change the date to the next date

I have a requirement where I need to duplicate the present record with data column update to the next date.
I have table data like below:
cobdate system b_id b_type L_TYPE lode symbol
------------------------------------------------------------
20150205 M N1 F L P T
20150205 M N1 F L P E
20150205 M N1 F L P E
I want to insert the same data for the next day in the same table.
After insertion I want the data in the table to be like below:
cobdate system b_id b_type L_TYPE lode symbol
-------------------------------------------------------------
20150206 M N1 F L P T
20150206 M N1 F L P E
20150206 M N1 F L P E
Because cobdate is a number, you need to transform it to date, add one day(date operation), then tranform it back to number:
insert into table(
cobdate,
system,b_id, b_type, L_TYPE, lode, symbol
)
select
to_char(to_date(cobdate,'yyyymmdd')+1,'yyyymmdd'),
system,b_id, b_type, L_TYPE, lode, symbol
from table
where cobdate='20150205';
However, you should take note that dates should be stored as DATE, not numbers, not varchars, nor spreaded on three or more columns(ex year, month, day).
Obligatory chiding: You should store dates as DATEs, not as NUMBERs. That said, to add one day to a date stored as a number should not be difficult:
INSERT INTO mytable ( cobdate, system, b_id, b_type, l_type, lode, symbol )
SELECT TO_NUMBER( TO_CHAR( TO_DATE(cobdate, 'YYYYMMDD') + 1, 'YYYYMMDD' ) )
, system, b_id, b_type, l_type, lode, symbol
FROM mytable
WHERE cobdate = 20150205;

How to exclude holidays between two dates?

I have two dates and I have to find out the number of Sundays and holidays fall between those two dates. Can I do this using BETWEEN? If so, how?
SELECT date1, date2, trunc(deposit_date - transaction_date) TOTAL
FROM Table_Name FULL OUTER JOIN Holidays ON date2 = hdate
WHERE hdate IN (date1, date2)
Using this I can definitely check whether there is a holiday on either of the two days, i.e. date1 or date2 but what I am not able to find out that whether there lies a holiday or a Sunday between these two dates. Help!
The solution you've posted is horribly inefficient; you can do all of this in a single SQL statement:
Firstly generate all possible dates between the two you have:
select trunc(:min_date) + level - 1
from dual
connect by level <= trunc(:min_date) - trunc(:max_date)
Then use your HOLIDAY table to restrict to what you want:
with all_dates as (
select trunc(:min_date) + level - 1 as the_date
from dual
connect by level <= trunc(:min_date) - trunc(:max_date)
)
select count(*)
from all_dates a
left outer join holiday b
on a.the_date = b.hdate
where b.hdate is null
and to_char(a.the_date, 'DY') <> 'SUN'
If you want to check if hdate is between the two dates you can query using
where hdate between date1 and date2
If you want to check if hdate is on the same day as date1 or date two you can query like this
where trunc(hdate) in (trunc(date1) ,trunc(date2))
The trunc function removed the time.
You should create a table with the holidays and maintain it on your own.
CREATE TABLE holidays
(
holiday VARCHAR2(100)
, d_date DATE
);
INSERT INTO holidays VALUES ('National Developer Day', DATE'2013-06-01');
SELECT *
FROM holidays;
-- National Developer Day 2013-06-01 00:00:00
The rest is just a matter of a SQL statment
Scenario 1: EXISTS
SELECT COUNT
(
CASE
WHEN TRIM(TO_CHAR(d.start_date_level, 'DAY')) = 'SUNDAY'
OR CASE
WHEN EXISTS (SELECT 1 FROM holidays h WHERE d.start_date_level = h.d_date)
THEN 1
ELSE NULL
END = 1
THEN 1
ELSE NULL
END
) AS holiday_check
FROM
(
SELECT start_date + (LEVEL - 1) AS start_date_level
FROM
(
SELECT start_date, end_date, end_date - start_date AS diff_date
FROM
(
SELECT TRUNC(ADD_MONTHS(SYSDATE, -2)) AS start_date
, TRUNC(SYSDATE) AS end_date
FROM DUAL
)
)
CONNECT BY
LEVEL <= (diff_date + 1)
) d
Scenario 2: LEFT JOIN
SELECT COUNT
(
CASE
WHEN TRIM(TO_CHAR(d.start_date_level, 'DAY')) = 'SUNDAY'
OR h.d_date IS NOT NULL
THEN 1
ELSE NULL
END
) AS holiday_check
FROM
(
SELECT start_date + (LEVEL - 1) AS start_date_level
FROM
(
SELECT start_date, end_date, end_date - start_date AS diff_date
FROM
(
SELECT TRUNC(ADD_MONTHS(SYSDATE, -2)) AS start_date
, TRUNC(SYSDATE) AS end_date
FROM DUAL
)
)
CONNECT BY
LEVEL <= (diff_date + 1)
) d
LEFT JOIN holidays h
ON d.start_date_level = h.d_date
9 Sundays + 1 "National Developer Day" = 10
CREATE OR REPLACE FUNCTION workdays (dt1 DATE, dt2 DATE) RETURN NUMBER IS
weekday_count NUMBER := 0;
date1 DATE := dt1;
date2 DATE := dt2;
cur_dt date;
holiday_count number;
begin
if date1 = date2 then
return 0;
end if;
cur_dt := transaction_date;
while cur_dt <= date2 loop
if cur_dt = date2 then
null;
else
SELECT count(*) INTO holiday_count
FROM holiday
WHERE hdate = cur_dt;
IF holiday_count = 0 THEN
IF to_char(cur_dt,'DY') NOT IN ('SUN') THEN
weekday_count := weekday_count + 1;
END IF;
END IF;
END IF;
cur_dt := cur_dt +1;
END LOOP;
RETURN weekday_count;
END;
And then I queried my database and got the right results. Do post if you have an optimal solution for this.
Here is an even better and efficient solution to the problem,
SELECT A.ID,
COUNT(A.ID) AS COUNTED
FROM tableA A
LEFT JOIN TableB B
ON A.tableB_id=B.id
LEFT JOIN holiday C
ON TRUNC(C.hdate) BETWEEN (TRUNC(a.date1) +1) AND TRUNC(B.date2)
WHERE c.hdate IS NOT NULL
GROUP BY A.ID;
where TableA contains date1 and tableB contains date2. Holiday contains the list of holidays and Sundays. And this query excludes 'date1' from the count.
RESULT LOGIC
trunc(date2) - trunc(date1) = x
x - result of the query
Make a table T$HOLIDAYS with your holidays (HDATE column). These dates will be excluded from calculation of working days within given period (sdate is start date and edate end date of period). Here is the function that calculates working days within given period excluding holidays, saturdays and sundays:
CREATE OR REPLACE FUNCTION WorkingDays(sdate IN DATE,edate IN DATE) RETURN NUMBER IS
days NUMBER;
BEGIN
WITH dates AS (SELECT sdate+LEVEL-1 AS d FROM DUAL CONNECT BY LEVEL<=edate-sdate+1)
SELECT COUNT(*) INTO days
FROM dates
WHERE d NOT IN (SELECT hdate FROM t$holidays) --exclude holidays
AND TO_CHAR(d,'D') NOT IN (6,7); --exclude saturdays + sundays
RETURN days;
END WorkingDays;
/
select sum(qq) from (
select case when to_number(to_char((trunc(sysdate-10) + level - 1),'D'))<=5 then 1 else 0 end as qq
from dual
connect by level <= trunc(sysdate) - trunc(sysdate-10))

Resources