Oracle SQL Using Variables Not Running - sql

This is probably an elementary question, but I'm new to Oracle SQL. I'm trying to get the SQL below to execute in Oracle SQL Developer. The error information is below the code. I've modified the code since I pasted the error message. Line 28 is the last line in the code, "END;" Line 14 column 1 refers to the word "Select".
DECLARE
v_StartDate Date := &StartDate;
v_EndDate Date := &EndDate;
SET v_StartDate := CASE &StartDate
WHEN TO_DATE('01/01/1900','MM/DD/YYYY')
THEN LAST_DAY(ADD_MONTHS(trunc(current_date),-2))
ELSE TO_DATE(&StartDate - 1) END;
SET v_EndDate := CASE &StartDate
WHEN TO_DATE('01/01/1900','MM/DD/YYYY')
THEN LAST_DAY(ADD_MONTHS(&EndDate,-1))
ELSE TO_DATE(&EndDate + 1) END;
BEGIN
Select *
From
Table
Where date_value > v_StartDate
and date_value < v_EndDate
END;
Error report -
ORA-06550: line 28, column 24:
PL/SQL: ORA-00933: SQL command not properly ended
ORA-06550: line 14, column 1:
PL/SQL: SQL Statement ignored
ORA-06550: line 28, column 27:
PLS-00103: Encountered the symbol "end-of-file" when expecting one of the following:
( begin case declare end exception exit for goto if loop mod
null pragma raise return select update while with
<< continue close current delete fetch lock
insert open rollback savepoint set sql execute commit forall
merge pipe purge json_exists json_value json_query
json_object json_array
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:

There are several things wrong with your code. I suggest you start with a small piece of code that works and then add statement by statement. That will allow you to see what is wrong and fix it. Once you have an accumulated set of syntax errors it becomes difficult to debug.
There are comments where the code has errors:
DECLARE
v_StartDate Date := &StartDate;
v_EndDate Date := &EndDate;
-- issues below:
-- 1. SET is not oracle syntax. To assign a variable, use the := operator
-- without the SET word.
-- 2. you cannot assign variables in the declaration section, unless you
-- declare and assign in the same statement. This part should go after
-- the BEGIN keyword
-- 3. Why would you use the bind variable if you already assigned it
-- above ??
SET v_StartDate := CASE &StartDate
WHEN TO_DATE('01/01/1900','MM/DD/YYYY')
THEN LAST_DAY(ADD_MONTHS(trunc(current_date),-2))
ELSE TO_DATE(&StartDate - 1) END;
SET v_EndDate := CASE &StartDate
WHEN TO_DATE('01/01/1900','MM/DD/YYYY')
THEN LAST_DAY(ADD_MONTHS(&EndDate,-1))
ELSE TO_DATE(&EndDate + 1) END;
BEGIN
-- issue below
-- you cannot just select in pl/sql, you need to SELECT INTO (if there is
-- a single row) or BULK COLLECT INTO (if you have multiple rows)
Select *
From
Table
Where date_value > v_StartDate
and date_value < v_EndDate
END;

I'm sorry to have to say it, but your code "has more errors than an early Met's game".
The key word SET belongs as a clause of the UPDATE statement. You have to UPDATE statements. If you just want to set the value of a variable, the syntax is simply
v_StartDate := some_value
And you have already set the value of v_StartDate with a parameter in you DECLARE section, so what are you trying to do with it now?
The keyword WHEN requires a comparison, but your usage
WHEN TO_DATE('01/01/1900','MM/DD/YYYY')
THEN LAST_DAY(ADD_MONTHS(trunc(current_date),-2))
Is not comparing the first arugment (TO_DATE ....) with anything.
You are trying to trunc(current_date) but 'current_date' is not defined -- and it's not a key word or reserved word. Perhaps you meant 'sysdate'.

Related

Why a type cannot be constrained?

I am struggling with the following code:
DECLARE
TOTACID TAB_OF_ID(50);
RES NUMBER;
BEGIN
SELECT DISTINCT ID INTO TOTACID
FROM TABLE_B;
FOR indx IN 1 .. TOTACID.COUNT
LOOP
RES := F_IMPORT(TOTACID(indx));
DBMS_OUTPUT.PUT_LINE ('Moved ID ' || RES);
END LOOP;
END;
/
When I run it, it fails with the error:
Error report -
ORA-06550: line 2, column 11:
PLS-00566: type name "TAB_OF_ID" cannot be constrained
ORA-06550: line 5, column 19:
PL/SQL: ORA-00932: inconsistent datatypes: expected UDT got NUMBER
ORA-06550: line 5, column 3:
PL/SQL: SQL Statement ignored
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
Where TAB_OF_ID has been declared as follows:
create or replace TYPE TAB_OF_ID AS table of NUMBER(19,2);
I don't understand what is wrong. It seems that I cannot declare TOTACID TAB_OF_ID(50) but in a function I created some days ago I could declare LIS_ID TAB_OF_ID := TAB_OF_ID(50); and it works properly.
What is the difference with the script I have here?
Obviously TOTACID TAB_OF_ID(50) is different to LIS_ID TAB_OF_ID := TAB_OF_ID(50); The command is like
{variable name} {data type} := {inital value};
where := {inital value} is optional.
TOTACID TAB_OF_ID(50) would mean
{variable name} {inital value};
which is not valid syntax.
You can not declare the variable by assigning your table a fixed number of records, so you need something like:
DECLARE
TOTACID TAB_OF_ID;
RES NUMBER;
BEGIN
SELECT DISTINCT ID bulk collect INTO TOTACID
FROM TABLE_B;
...
END;
/
Also, notice that you are fetching more than one value, so you need BULK COLLECT INTO.
About
LIS_ID TAB_OF_ID := TAB_OF_ID(50);
here you are not declaring a variable with a given number of records, but you are assigning to a variable the 50th value of the table.

Incomplete/Malformed cursor

I have a PL/SQL script to perform some aggregation tasks. I am having compilation errors, logic is not top priority at this moment as that can be changed once the errors are resolved. The script is as follows :
SET SERVEROUTPUT ON;
ALTER SESSION SET NLS_DATE_FORMAT = 'dd-MON-yy';
CREATE OR REPLACE PROCEDURE updateFeaturePerformanceTable
(noOfDays IN NUMBER, runDate IN DATE, timeSpan IN VARCHAR2)
AS
CURSOR c_feature_performance IS
SELECT distinct mkt_id,dow,device_type,feature_name
FROM gfmdev.feature_performance
WHERE timespan = 'ONE_DAY'
AND feature_performance_day >= TO_DATE('17-AUG-15','dd-MON-yy');
rowsExtracted c_feature_performance%ROWTYPE;
extractDate DATE;
timespan_test varchar2(20);
BEGIN
OPEN c_feature_performance;
extractDate := runDate - noOfDays;
timespan_test := timeSpan;
LOOP
FETCH c_feature_performance INTO rowsExtracted;
EXIT WHEN c_feature_performance%NOTFOUND;
dbms_output.put_line(extractDate || ' ' || timespan_test);
INSERT INTO gfmdev.feature_performance
SELECT
rowsExtracted.mkt_id,
rowsExtracted.dow,
rowsExtracted.device_type,
rowsExtracted.feature_name,
SUM(OPS),
SUM(GV_COUNT),
runDate,
timespan_test
FROM gfmdev.feature_performance
WHERE feature_performance_day BETWEEN extractDate AND runDate
AND timespan = 'ONE_DAY'
AND mkt_id = rowsExtracted.mkt_id
AND dow = rowsExtracted.dow
AND device_type = rowsExtracted.device_type
AND feature_name = rowsExtracted.feature_name
group by mkt_id, dow, device_type, feature_name, timespan;
END LOOP;
CLOSE c_feature_performance;
EXCEPTION
WHEN TOO_MANY_ROWS THEN
dbms_output.put_line('Trying to insert too many rows in SELECT...INTO');
ROLLBACK;
WHEN NO_DATA_FOUND THEN
dbms_output.put_line('No rows returned in SELECT...INTO');
ROLLBACK;
WHEN STORAGE_ERROR THEN
dbms_output.put_line('Too much data to handle! Storage error');
ROLLBACK;
WHEN OTHERS THEN
dbms_output.put_line('Oops! Something went wrong');
ROLLBACK;
RAISE;
END updateFeaturePerformanceTable;
Show compilation errors:
SHOW ERRORS PROCEDURE updateFeaturePerformanceTable;
Run the procedure:
DECLARE
runDate DATE;
BEGIN
FOR j IN 0 .. 5 LOOP
SELECT (TO_DATE('17-AUG-15','dd-MON-yy') + j) INTO runDate FROM dual;
updateFeaturePerformanceTable(6,runDate, 'ONE_WEEK');
END LOOP;
DBMS_OUTPUT.PUT_LINE(' WEEKLY RECORDS UPDATED ');
FOR j IN 0 .. 28 LOOP
SELECT (TO_DATE('17-AUG-15','dd-MON-yy') + j) INTO runDate FROM dual;
updateFeaturePerformanceTable(29,runDate, 'ONE_MONTH');
END LOOP;
DBMS_OUTPUT.PUT_LINE(' MONTHLY RECORDS UPDATED ');
COMMIT;
END;
/
When I execute it I get the following error message :
Errors for PROCEDURE UPDATEFEATUREPERFORMANCETABLE:
LINE/COL ERROR
-------- -----------------------------------------------------------------
4/9 PLS-00341: declaration of cursor 'C_FEATURE_PERFORMANCE' is
incomplete or malformed
5/3 PL/SQL: SQL Statement ignored
6/15 PL/SQL: ORA-00942: table or view does not exist
8/16 PL/SQL: Item ignored
16/3 PL/SQL: SQL Statement ignored
16/36 PLS-00320: the declaration of the type of this expression is
incomplete or malformed
21/3 PL/SQL: SQL Statement ignored
LINE/COL ERROR
-------- -----------------------------------------------------------------
36/22 PL/SQL: ORA-00904: "ROWSEXTRACTED"."FEATURE_NAME": invalid
identifier
36/22 PLS-00320: the declaration of the type of this expression is
incomplete or malformed
updateFeaturePerformanceTable(6,runDate, 'ONE_WEEK');
*
Any help on where I am going wrong is highly appreciated?
PL/SQL is a framework for running SQL statements programmatically. So often we find that PL/SQL errors are caused by the SQL errors in our code.
That is the case here. You have several PL/SQL errors indicating that the Cursor declaration is invalid. And why is it invalid? This line holds the answer:
6/15 PL/SQL: ORA-00942: table or view does not exist
So the problem is, the owner of the procedure UPDATEFEATUREPERFORMANCETABLE (ugly name by the way) does not have rights on gfmdev.feature_performance.
To solve, the table owner GFMDEV needs to grant SELECT and INSERT directly to the account which owns this procedure.
SQL> conn gfmdev/password
SQL> grant select, insert on feature_performance to whoever;
Note that granting privileges through a view won't cut it. The Oracle security model only permits us to build objects - PL/SQL programs, views - with privileges granted directly to our user.

Reduce the value of a vehicle every month

What I am trying to do is to reduce the value of every vehicle in the 'Vehicle' table so that when the date reaches one month past the 'LastUpdate' value the 'Value' column is reduced by 2.5%. The trigger should run AFTER LOGON ON DATABASE. The problem is, a DBA may not logon to the database every day, so if it is has been six months since the last logon, the trigger will loop through, reduce the value by 2.5% and do ADD_MONTHS(LastUpdate, 1).
My code for the function that will calculate the value is:
REATE OR REPLACE FUNCTION fn_Vehicle_Value
(VehicleNumber IN NUMBER,
VehicleValue IN OUT NUMBER)
RETURN NUMERIC
IS
BEGIN
VehicleValue := VehicleValue - (VehicleValue * 0.025);
RETURN VehicleValue;
END;
/
This is my attempt at creating the system trigger:
CREATE OR REPLACE TRIGGER tg_VehicleDepreciate
AFTER LOGON ON DATABASE
IS
CURSOR vehicle_cur IS SELECT "VALUE", LastUpdate FROM Vehicle;
BEGIN
FOR vehicle_rec IN vehicle_cur LOOP
WHILE LastUpdate < SYSDATE LOOP
LastUpdate."Value" := fn_Vehicle_Update("VALUE");
UPDATE Vehicle
SET LastUpdate := ADD_MONTHS(LastUpdate, 1)
WHERE Vehicle# = vehicle_cur.Vehicle#;
END LOOP;
EXIT WHEN vehicle_cur%NOTFOUND;
END LOOP
END;
/
From what I can tell, my function is right. But the trigger does not compile and produces the following error report:
Error report -
ORA-04079: invalid trigger specification
04079. 00000 - "invalid trigger specification"
*Cause: The create TRIGGER statement is invalid.
*Action: Check the statement for correct syntax.
I am guessing it is a syntax error, but there may also be a logical error that I cannot work out.
SHOW ERRORS after compiling your trigger would reveal all errors.
Here are few..
1) in update, it is just SET somecolumn = Somevalue
2) oracle implicitly opens the cursor and closes to, when used with a FOR loop.
3) after using FOR loop,the fetched results should be used like.. Forloopvariable.column-name
4) added Vehicle# to your cursor.
5) added V_date logic.
CREATE OR REPLACE TRIGGER tg_VehicleDepreciate
AFTER LOGON ON DATABASE
IS
CURSOR vehicle_cur IS SELECT "VALUE", LastUpdate ,Vehicle# FROM Vehicle;
V_date DATE;
BEGIN
FOR vehicle_rec IN vehicle_cur LOOP
V_date := vehicle_rec.LastUpdate;
WHILE V_date < SYSDATE LOOP
/* what are you trying here? */
---vehicle_rec."Value" := fn_Vehicle_Update("VALUE");
UPDATE Vehicle
SET LastUpdate = ADD_MONTHS(LastUpdate, 1)
WHERE Vehicle# = vehicle_rec.Vehicle#;
V_date := ADD_MONTHS( V_date,1);
END LOOP;
END LOOP
END;
/

cant compile any cursor example

I'm trying to make any cursor example working, but just cant make it happen.
IDE: Oracle SQL developer
database: 10g sql oracle
I've tried this three examples, but it didn't compile well. Can someone provide me with working examples?
First one:
EDIT: works! just had 'where where'
DECLARE
CURSOR person_data_cur
as
SELECT *
FROM personal_data
WHERE where name='Karol';
BEGIN
FOR person_data
IN person_data_cur
LOOP
DBMS_OUTPUT.put_line (
person_data.surname);
END LOOP;
END;
and this:
DECLARE my_cursor1 CURSOR FOR
SELECT name, surname
FROM personal_data
WHERE name='Karol';
^error:
Error report -
ORA-06550: row 1, column 27:
PLS-00103: found symbol "FOR" when expected one of following:
:= . ( # % ; not null range default character
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
or even this:
EDIT: this one is OK, just my IDE ignored first two lines, and executed others... but i guess it was OK since it wasnt inside any block or procedure
CURSOR c1
IS
SELECT course_number
FROM courses_tbl
WHERE course_name = name_in;
For Second Example : Your syntax is incorrect.
The pseudo code for the cursor is :
Declare
Cursor Cursor_name
is
select * from table where <Conditions>;
Begin
For cur_Rec in cursor_name
Loop
<what you want to do>
End Loop;
End;
For the third example, I believe name_in is an input parameter, please correct the syntax to :
CURSOR c1 (name_in VARCHAR2)
IS
SELECT course_number
FROM courses_tbl
WHERE course_name = name_in;
Please refer Cursor Declaration for more details

Select a single column value and store it in variable oracle sql

I want to grab a particular column value a.id and store it into a variable v_id. Then use this value to pass into a stored procedure.
DECLARE v_id a.id%TYPE;
BEGIN
SELECT id into v_id from a where a.name='test' and rownum <2 order by id desc;
Print v_id;
doSomething(v_id);
END;
/
I'm getting this error in Oracle SQL Developer:
Error report: ORA-06550: line 3, column 7: PLS-00103: Encountered the
symbol "V_ID" when expecting one of the following:
:= . ( # % ; The symbol ":=" was substituted for "V_ID" to
continue.
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
If you want to use rownum and order by you have to put the order by in a sub-query. There is no other way to guarantee that you get the correct value.
It's also good practice to deal with the possibility that there may not be an id that matches your query. I've added an additional begin... end; block to deal with this.
declare
v_id a.id%type;
begin
begin
select id into v_id
from ( select id
from a
where name = 'test'
order by id desc )
where rownum < 2
;
exception when no_data_found then
v_id := null;
end;
dbms_output.put_line(v_id);
doSomething(v_id);
end;
/
As #raukh noted (whilst I was writing this!) the problem is print, which should be dbms_output.put_line()
This:
Print v_id;
is not valid. Probably you meant:
dbms_output.put_line(v_id);
? (Note that you may need to run
set serveroutput on;
beforehand in order for the above to have an effect.)
PRINT isn't a valid PL/SQL command, so that's going to create a problem. Perhaps you wanted
DECLARE
v_id a.id%TYPE;
BEGIN
SELECT id
into v_id
from (SELECT id
FROM a
where a.name='test'
order by id desc)
where rownum < 2;
dbms_output.put_line( v_id );
doSomething(v_id);
END;
/