PLS-00201: identifier 'D.HOLIDAY_DATE' must be declared - oracle

here is my code:
DECLARE
V_loop number(2); -------declare the loop times
begin
looptimes(V_loop); ------set the forcast times from parameter table
loop
IF V_loop > 0 ------forcast
THEN
IF to_char((sysdate+V_loop-7),'dd/mon/yy') not like To_chat((d.holiday_date),'dd/mon/yy')----------condition that perivous 'day' not holiday
then
insert into local_rm16(tni, lr, frmp, day, hh, volume)
SELECT TNI, LR, FRMP, sysdate+v_loop, HH, AVG(VOLUME)
FROM V_nem_rm16,DBP_holiday d
where to_char(day, 'Day') = to_char(sysdate+V_loop, 'Day')
group by day,hh, lr, frmp,tni
order by 1;
else
exit;
end if;
V_loop := V_loop -1;
ELSE
exit;
ENd if;
END loop;
end;
i dont know howto declare holiday_date in if conditions, can anyone help me, thx

You have written to_chat instead of to_char:
IF to_char((sysdate+V_loop-7),'dd/mon/yy') not like To_chat((d.holiday_date),'dd/mon/yy')
You can't use d before you defined it. It's defined in SELECT as an alias to DBP_holiday table, but you use it earlier in IF expression. You should think once again about your code, because you can't do it like this (maybe you should consider using cursor loop).

Related

PLS-00103 error while trying to compare numbers

Is this prcedure syntaxically wrong? It seems that there is a problem with my if than block. I kepp getting
PLS-00103: Encountered the symbol ")" when expecting one of the
following:
(
CREATE OR REPLACE PROCEDURE Verif(TAB VARCHAR2) IS
MAX NUMBER;
TEMP NUMBER;
BEGIN
FOR i IN (SELECT * FROM CLIENTS1_1 WHERE NOT REGEXP_LIKE (COL2, (SELECT REGULAREXPR FROM REGULAREXPRES WHERE CATEGORY='ABR'))) LOOP
MAX:=0;
FOR j IN (SELECT * FROM ABR) LOOP
SELECT UTL_MATCH.JARO_WINKLER_SIMILARITY(i.Col2, j.ABR) INTO TEMP FROM DUAL;
IF (TEMP >= MAX) THEN
DBMS_OUTPUT.PUT_LINE(TEMP);
end if;
END LOOP;
END LOOP;
END;
/
I did all the tests. All select queries return real values.
Thanks for your help.
It was a stupid mistake. Just needed to replace MAX (which is a key word) by another var name.
Thanks to Barbaros Ozhan.

How to print a particular select statement three times in oracle?

This is the code
declare
a integer;
begin
select to_char(to_date('1/1/2017 ','mm/dd/yyyy') + level -1) into a from dual
connect by level <=365;
for a in 1..3 loop
dbms_output.put_line(a);
end loop;
end;
Error occurring is exact fetch requested more no of rows
Please help
You are trying to get multiple value in a scaler variable.
Try this:
begin
for i in (select to_char(to_date('1/1/2017 ','mm/dd/yyyy') + level -1) col
from dual
connect by level <=365) loop
for j in 1..3 loop
dbms_output.put_line(i.col);
end loop;
end loop;
end;
/
1st of all, please be aware about the fact that you declared the "a" variable as integer but then you assign a varchar2 to it.
2nd, I was testing your code and it seems that there is a problem with level <= 365.
I changed it into level = 365 and it seemed to return the expected result.
declare
a integer;
begin
select to_char(to_date('1/1/2017 ','mm/dd/yyyy') + level -1) into a from dual
-- connect by level <= 365;
connect by level = 365;
for a in 1..3 loop
dbms_output.put_line(a);
end loop;
end;

PLS-00103: Encountered the symbol "1" when expecting one of the following: (

Wrote the following PLSQL script to produce a report and am getting the error messages
Error at line 5
ORA-06550: line 61, column 18:
PLS-00103: Encountered the symbol "1" when expecting one of the following:
(
I've been through the code many times and I cannot find the error. Any help would be greatly appreciated.
I'm currently working in Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - 64bit Production
SET serveroutput ON size 1000000;
DECLARE
TYPE TITLE_RECORD_TYPE IS RECORD
(id number(19),
gaid varchar2(20),
artist_legal_name varchar2(510),
artist_display_title varchar2(510),
display_title varchar2(510),
category varchar2(255),
type varchar2(255),
sub_type varchar2(255));
TITLE_RECORD TITLE_RECORD_TYPE;
v_title varchar2(510);
v_artist varchar2(510);
v_total_rows_error number(20) := 0;
v_row_count number(10) := 0;
v_error_desc varchar2(200) := NULL;
v_error_code number(19);
CURSOR ARTIST_TITLE_CURSOR is
select track_artist,track_title
from asset_artist_title;
CURSOR QUERY_CURSOR is
select distinct g1.gaid,g2.legal_name,g1.artist_display_title,
g1.display_title,g1.category,g1.type,g1.sub_type
from gcdm_app_rpt.rpt_asset g1,
gcdm_app_rpt.rpt_artist g2
where g1.artist_id = g2.id
and g1.is_deleted <> 'Y'
and g1.is_core = 'Y'
and g2.is_core = 'Y'
and g1.title like v_title||'%'
and g1.artist_display_title like v_artist||'%';
BEGIN
OPEN ARTIST_TITLE_CURSOR;
LOOP
FETCH ARTIST_TITLE_CURSOR into v_artist,v_title;
EXIT WHEN ARTIST_TITLE_CURSOR%NOTFOUND or ARTIST_TITLE_CURSOR%NOTFOUND IS NULL;
SELECT count(*)
INTO v_row_count
FROM gcdm_app_rpt.rpt_asset g1,
gcdm_app_rpt.rpt_artist g2
WHERE g1.artist_id = g2.id
AND g1.is_core = 'Y'
AND g1.is_deleted <> 'Y'
AND g2.is_core = 'Y'
AND g1.title like v_title||'%'
AND g1.artist_display_title like v_artist||'%';
IF v_row_count < 1 THEN
v_error_desc := 'Matching Asset record for '||v_artist||' - '||v_title||' not found';
DBMS_OUTPUT.PUT_LINE('Error: '||v_error_desc||'.');
v_row_count := 0;
v_total_rows_error := v_total_rows_error + 1;
ELSE
OPEN QUERY_CURSOR
FOR i in 1..ARTIST_TITLE_CURSOR
LOOP
FETCH QUERY_CURSOR into TITLE_RECORD;
EXIT WHEN QUERY_CURSOR%NOTFOUND or QUERY_CURSOR%NOTFOUND IS NULL;
DBMS_OUTPUT.PUT_LINE(title_record.id,title_record.gaid,title_record.artist_legal_name,title_record.artist_display_name,
title_record.display_title,title_record.category,title_record.type,title_record.sub_type);
END LOOP;
CLOSE QUERY_CURSOR;
v_row_count := 0;
END IF;
END LOOP;
CLOSE ARTIST_TITLE_CURSOR;
DBMS_OUTPUT.PUT_LINE(chr(0));
IF v_total_rows_error > 0 THEN
DBMS_OUTPUT.PUT_LINE('Total Rows in error: '||v_total_rows_error);
END IF;
DBMS_OUTPUT.PUT_LINE(CHR(0));
EXCEPTION
WHEN OTHERS THEN
v_error_desc := SQLERRM;
v_error_code := SQLCODE;
DBMS_OUTPUT.PUT_LINE('Error: '||v_error_desc||' - '||v_error_code);
END;
It's line 67 in what you've posted, not 61, but still; this line is not right:
FOR i in 1..ARTIST_TITLE_CURSOR
You're trying to loop over a range of numbers - perhaps you wanted the number of records returned by the cursor, which you can't get - but your end 'number' is a cursor, so not legal in that context.
But it seems to be completely out of place anyway as you're looping over the QUERY_CURSOR records, so I wouldn't think the ARTIST_TITLE_CURSOR is relevant at this point. And you aren't attempting to use i. It looks like you can just remove that line.
More importantly, the previous line is missing a semi-colon:
OPEN QUERY_CURSOR;
Because it doesn't have one it's seeing the FOR and expecting a cursor query.
Following up on comments about why you have that FOR 1..v_row_count, it's still a bit redundant. You're limiting the number of fetches you do to match the count you got previously, from essentially the same query as you have in the cursor, which means you don't quite ever hit the EXIT WHEN QUERYCURSOR%NOTFOUND condition - that would come from the v_row_count+1 loop iteration. Normally you wouldn't know how many rows you expect to see before you loop over a cursor.
You don't really need to know here. The count query is repetitive - you're querying the same data you then have to hit again for the cursor, and you have to maintain the query logic in two places. It would be simpler to forget the count step, and instead keep a counter as you loop over the cursor; then handle the zero-rows condition after the loop. For example:
DECLARE
...
BEGIN
OPEN ARTIST_TITLE_CURSOR;
LOOP
FETCH ARTIST_TITLE_CURSOR into v_artist,v_title;
EXIT WHEN ARTIST_TITLE_CURSOR%NOTFOUND;
-- initialise counter for each ARTIST_TITLE
v_row_count := 0;
OPEN QUERY_CURSOR;
LOOP
FETCH QUERY_CURSOR into TITLE_RECORD;
EXIT WHEN QUERY_CURSOR%NOTFOUND;
-- increment 'found' counter
v_row_count := v_row_count + 1;
DBMS_OUTPUT.PUT_LINE(title_record.id
||','|| title_record.gaid
||','|| title_record.artist_legal_name
||','|| title_record
||','|| artist_display_name
||','|| title_record.display_title
||','|| title_record.category
||','|| title_record.type
||','|| title_record.sub_type);
END LOOP;
CLOSE QUERY_CURSOR;
-- now check if we found anything in the QUERY_CURSOR loop
IF v_row_count < 1 THEN
v_error_desc := 'Matching Asset record for '||v_artist||' - '||v_title||' not found';
DBMS_OUTPUT.PUT_LINE('Error: Matching Asset record for '
|| v_artist || ' - ' || v_title || ' not found.');
v_total_rows_error := v_total_rows_error + 1;
END IF;
END LOOP;
CLOSE ARTIST_TITLE_CURSOR;
--DBMS_OUTPUT.PUT_LINE(chr(0));
-- presumably this was meant to put out a blank line; use this instead
DBMS_OUTPUT.NEW_LINE;
IF v_total_rows_error > 0 THEN
DBMS_OUTPUT.PUT_LINE('Total Rows in error: '||v_total_rows_error);
END IF;
--DBMS_OUTPUT.PUT_LINE(CHR(0));
DBMS_OUTPUT.NEW_LINE;
END;
I've also taken out the exception handler because it isn't really adding anything; you'd see the code and message without it, even if you didn't have server output on; and catching WHEN OTHERS is a bad habit to get into.
You also don't need to declare your record type. You could use an implicit cursor anyway and avoid the type and variable completely, but even with the cursor definition you have, you could put this afterwards instead:
TITLE_RECORD QUERY_CURSOR%ROWTYPE;
There are various ways to open and loop over cursors, and you're using one of the more explicit ones - which isn't a bad thing for learning about them, but be aware of the options too.

Need an alternative solution to this oracle query?Without using (flag) variable

Question:
Create a Doctor table (Docname, Qualification, Specialization, Working_shift).
Use parameterized cursor to check the availability of doctors given the specialization
and working shift of the day to serve the patients
I am just learning databases so if the question may seem trivial i apologize for that.
Getting the desired output on inputting the values but i need an alternative way to solve the question without using flag variable (so that i could get the exception)...if i don't use the flag it prints the exception as well as the docname and qualification
I am using oracle(cursor in a normal pl/sql block) to execute this query.
Solution:
--table creation
create table doctor
(
docname varchar2(20),
qualification varchar2(20),
specialization varchar2(20),
shift varchar2(20)
)
my solution
declare
cursor c1 (specialization varchar2,shift varchar2) is select docname,qualification from doctor
where specialization='&sp' and shift='&shift'
sp doctor.specialization%type;
shift doctor.shift%type;
flag number(10);
begin
flag:=0;
for r1 in c1(sp,shift)
loop
if c1%found then
flag:=1;
dbms_output.put_line('Doctor is available');
dbms_output.put_line('Docname: '||r1.docname);
dbms_output.put_line('qualification: '||r1.qualification);
else
flag:=0;
end if;
end loop;
if flag=0 then
dbms_output.put_line('Invalid specialization/shift');
end if;
end;
Try given below code
declare
cursor c1 (specialization varchar2,shift varchar2)
is
select docname,qualification
from doctor
where specialization='&sp'
and shift='&shift'
sp doctor.specialization%type;
shift doctor.shift%type;
flag number(10);
begin
flag:=0;
for r1 in c1(sp,shift)
loop
if c1%found then
flag:=1;
dbms_output.put_line('Doctor is available');
dbms_output.put_line('Docname: '||r1.docname);
dbms_output.put_line('qualification: '||r1.qualification);
else
raise;
end if;
end loop;
exception
when others then
dbms_output.put_line('Invalid specialization/shift');
end;
You don't need to reset the flag within the loop, you already initialised it to 0 at the start of the procedure.
You dont need to check c1%found because you're inside the loop; by definition a record was found, otherwise it wouldn't go into your loop code.
Your cursor should use the variables provided, not the SQL*Plus substitution variables, e.g.:
cursor c1 (specialization varchar2,shift varchar2) is
select docname,qualification
from doctor
where doctor.specialization=c1.specialization
and doctor.shift=c1.shift;
If you don't want to have to use all those aliases, you can use a naming convention to distinguish between the different identifiers (shift vs shift), e.g.:
cursor c1 (i_specialization varchar2, i_shift varchar2) is
select docname,qualification
from doctor
where specialization=i_specialization
and shift=i_shift;
Note also, you missed a semicolon at the end of the query.
Finally:
If you change your loop as follows, it should work fine:
for r1 in c1(&sp,&shift)
loop
flag:=1;
dbms_output.put_line('Doctor is available');
dbms_output.put_line('Docname: '||r1.docname);
dbms_output.put_line('qualification: '||r1.qualification);
end loop;
Now, your last bit of code:
if flag=0 then
dbms_output.put_line('Invalid specialization/shift');
end if;
will work fine - it will only execute if flag is still 0 (i.e. the query found no rows).
If you do not use parameters in "c1" cursor you do not need it...
DECLARE
CURSOR c1 IS
SELECT docname, qualification
FROM doctor
WHERE specialization = '&sp'
AND shift = '&shift';
TYPE c1_ntt IS TABLE OF c1%ROWTYPE;
l_c1 c1_ntt;
BEGIN
OPEN c1;
FETCH c1 BULK COLLECT INTO l_c1;
CLOSE c1;
IF l_c1.COUNT = 0 THEN
RAISE_APPLICATION_ERROR(-20000, 'Invalid specialization/shift');
END IF;
FOR indx IN l_c1.FIRST..l_c1.LAST LOOP
DBMS_OUTPUT.PUT_LINE('Doctor is available');
DBMS_OUTPUT.PUT_LINE('Docname: ' || l_c1(indx).docname);
DBMS_OUTPUT.PUT_LINE('qualification: ' || l_c1(indx).qualification);
END LOOP;
END;

Why is my cursor only returning the top row?

Hello I'm a bit baffled that the cursor I have in this function is only returning the top row.
I've been comparing it to a few different examples I've seen and I just don't see what's wrong. Any guidance is greatly appreciated.
FUNCTION FS_A_FUNCTION
(
inDate DATE
)
RETURN VARCHAR2 IS
tAnswer VARCHAR2(1) := 'N';
tDates DATE;
CURSOR c1 IS
SELECT S.Dates FROM A_TABLE S;
BEGIN
OPEN c1;
LOOP
FETCH c1 INTO tDates;
EXIT WHEN c1%NOTFOUND;
END LOOP;
CLOSE c1;
IF inDate IN (tDates) THEN
tAnswer := 'Y';
END IF;
RETURN (tAnswer);
END FS_A_FUNCTION
Thanks in advance.
Not quite sure what you're expecting to happen. After your loop tDates will have a single value from whichever row the cursor saw last. As your select doesn't have an order by, that could be any value from your table. I think you may mean to be checking the value against inDate inside the loop.
I'm not sure why you're using a cursor at all, unless the real logic is more complicated. If you're doing what I think, you could just do something like:
FUNCTION FS_A_FUNCTION
(
inDate DATE
)
RETURN VARCHAR2 IS
tAnswer VARCHAR2(1);
BEGIN
select decode(max(dates), null, 'N', 'Y')
into tAnswer
from a_table
where dates = inDate;
RETURN tAnswer;
END FS_A_FUNCTION;
... or maybe a bit clearer bu the same logic:
FUNCTION FS_A_FUNCTION
(
inDate DATE
)
RETURN VARCHAR2 IS
tDates DATE;
BEGIN
select max(dates)
into tDates
from a_table
where dates = inDate;
IF tDates IS NULL THEN
RETURN 'N';
ELSE
RETURN 'Y';
END IF;
END FS_A_FUNCTION;
In both cases I'm using max() in case there are multiple rows with the same date.
You are testing if the inDate exists in the dates field of your table, but only after the loop ends, so the reference to tDates will be the last record of the query.
You can do this by simply checking if exists a record with the date:
cursor c1 is
select *
from A_TABLE
where Dates = inDate;
As you can see, there's no need to do a loop.

Resources