I'm trying to create a stored procedure that can only be executed in the month of march based on system date. Here is a snippot of such code:
CREATE PROCEDURE sp_time_window (
p_sales_ID in sales.sales_ID%TYPE,
p_product in sales.product%TYPE,
p_unitCost in sales.unitcost%TYPE,
p_quantity in sales.quantity%TYPE)
IS BEGIN
DECLAR v_date varchar(3)
BEGIN
SELECT TO_CHAR(sysdate,'MM') into v_date from duaL
IF (v_date in ('MAR')) THEN
INSERT INTO sales (sales_ID, product, unitcost, quantity) values
(p_sales_ID, p_ product, p_unitCost, p_quantity);
ENDIF;
END;
END;
/
ORACLE gives me this error:
LINE/COL ERROR
-------- ---------------------------------------------------
14/2 PL/SQL: SQL Statement ignored
16/5 PL/SQL: ORA-00933: SQL command not properly ended
please help
You have a redundant layer of BEGIN/END, and various typos, some of which I think you've just introduced creating the question, like DECLAR instead of DECLARE. But the first thing that might get that error is the missing semicolon after dual.
SELECT TO_CHAR(sysdate,'MM') into v_date from duaL;
You can assign the month value directly to the variable without the select from dual anyway:
v_date := TO_CHAR(sysdate,'MM');
... but as you have that defined as varchar2(3) and later look for MAR, that format mask should be MON not MM. However, using numbers is safer anyway, otherwise you need to be sure your session is in English. Your variable should be the appropriate type.
You also have a spaces in p_ product, and ENDIF instead of END IF, but again those might not be in your real code.
You can reduce what you have to:
CREATE OR REPLACE PROCEDURE sp_time_window (
p_sales_ID in sales.sales_ID%TYPE,
p_product in sales.product%TYPE,
p_unitCost in sales.unitcost%TYPE,
p_quantity in sales.quantity%TYPE)
AS
BEGIN
IF extract(month from sysdate) = 3 THEN
INSERT INTO sales (sales_ID, product, unitcost, quantity)
VALUES (p_sales_ID, p_product, p_unitCost, p_quantity);
END IF;
END;
/
The extract(month from sysdate) gets the month number from the date, so you can check if that is 3, as a number not a string. You also don't need the local v_date variable if you do that extraction in the IF clause.
Silently ignoring the insert seems odd, as the caller will no have no idea if that happens. And this won't stop inserts outside the procedure. In this case it might be appropriate to use a trigger that raises an exception if the month number is not 3.
Related
In DB2 it is possible to raise an error if a subquery returns no results with the help of coalesce and the raise_error scalar function. But how can this be done in oracle?
I checked scalar functions so far, but there is no raise error function.
example for db2 (note: the subquery needs to be replaced by something meaningful...):
SELECT
COALESCE(
(SELECT 1 FROM SYSIBM.SYSDUMMY1 LIMIT 0),
RAISE_ERROR('70NUL', 'Value is missing'))
FROM
SYSIBM.SYSDUMMY1;
UPDATE 1:
The use case is about finding a matching value in another table during an export of millions of records. The idea is to raise an error if there is no matching value so it is detected early and not afterwards.
The way you describe it it sounds as if you need to mark a number of records based on whenever some values exist in a table. If PLSQL is an option you can just use the no_data_found exception:
invalid_data CONSTANT NUMBER := -70;
DECLARE
l_var NUMBER;
BEGIN
SELECT 1
INTO l_var
FROM dual
WHERE 1 <> 1;
EXCEPTION WHEN no_data_found THEN
/* do your updating or error handling */ RAISE_APPLICATION_ERROR(invalid_data ,'Value is missing');
END;
You can use RAISE_APPLICATION_ERROR feature of oracle to resolve your problem. You can declare a procedure and define when to raise the exception in that procedure. Simply call the procedure to execute your task and it will raise the error whenever your given condition staisfies.
For knowing in details, please see the trapping user defined exceptions section of oracle documentation with example.
In Oracle, you'd use similar query:
SQL> select coalesce((select dummy from dual where 1 = 2), 'Value is missing') result from dual;
RESULT
----------------
Value is missing
SQL> select coalesce((select dummy from dual where 1 = 1), 'Value is missing') result from dual;
RESULT
----------------
X
SQL>
I don't speak MS SQL Server so I can't comment it.
Alternative to #Gnqz solution is to write a user function wrapper around raise_application_error() in conjunction with coalesce.
CREATE OR REPLACE FUNCTION raise_error
RETURN NUMBER
IS
BEGIN
raise_application_error(-70, 'Mapping value is missing');
RETURN(0);
END;
select coalesce((select 5 AS result from dual fetch first 1 row only), raise_error()) AS result from dual;
When I run declare query, it always gives me errors.
DECLARE
the_variable date;
BEGIN
SELECT MIN("Start Date") INTO the_variable FROM "Employee_Master";
END;
ORA-06550: line 2, column 20: PLS-00103: Encountered the symbol
"end-of-file" when expecting one of the following: := . ( # % ; not
null range with default character.
I am not sure where is the problem.
Works OK for me:
SQL> create table "Employee_Master" ("Start Date" date);
Table created.
SQL> insert into "Employee_Master" values (sysdate);
1 row created.
SQL> declare
2 the_variable date;
3 begin
4 select min("Start Date") into the_variable
5 from "Employee_Master";
6 end;
7 /
PL/SQL procedure successfully completed.
SQL>
Though, why, oh, why are you making your life miserable? Avoid double quotes while working with Oracle. If you do that, you always have to reference tables (and columns) using double quotes and matching letter case exactly as during creation process.
By default, Oracle stores everything as uppercase, but you can reference those objects any way you want (upper, lower, mixed case - doesn't matter). But, with double quotes, as I've said - exact matching is required.
By the way, screenshot you attached shows a lot of nothing and just a little bit of something. Couldn't you have taken a better screenshot?
On the SQL Fiddle website, you need to tell it that you are going to be using PL/SQL and a statement will be ended with a / terminator (and not by a ; semi-colon). To do this you need to click on the "Query Terminator" button (right of the "Run SQL" and "Edit Fullscreen" buttons) and change it from [;] to [/].
Then it will work:
SQL Fiddle
Oracle 11g R2 Schema Setup:
CREATE TABLE Employee_Master ( Start_Date DATE );
INSERT INTO Employee_Master ( Start_Date ) VALUES ( SYSDATE );
Query 1:
DECLARE
the_variable date;
BEGIN
SELECT MIN(Start_Date) INTO the_variable FROM Employee_Master;
END;
/
Results:
I have a simple test function where I'm passing in a specific ID (the primary key of the table I'm selecting from), and computing a simple function on it and the parameters.
The skeleton code and test:
create or replace function test(id varchar2, area float) return float is
theRow forest%ROWTYPE;
begin
select * into theRow from forest where Forest_No = id;
return area / theRow.Area;
end;
begin
select test('1', 16000) from dual;
end;
The output:
[2019-10-14 21:19:10] [65000][6550] ORA-06550: line 2, column 5:
[2019-10-14 21:19:10] PLS-00428: an INTO clause is expected in this SELECT statement
I am at a loss for what to do here, as far as I can tell the documentation and examples use the same order and syntax. I have tried moving the into clause to the end as in Postgresql, but that did not work.
What have I missed here?
Issue is in calling statement.
Whenever select statement is used in plsql block it must have into clause to assign return value to variable.
You should remove begin and end from your calling code:
--begin -- remove this
select test('1', 16000) from dual;
--end; -- remove this
Or if you want to use it in plsql block then add into clause:
Declare
Area_ float(precision);
begin
select test('1', 16000) into area_ from dual;
-- use area_ in your code wherever required
dbms_output.put_line('area: ' || area_);
end;
Cheers!!
I have following Store procedure in Oracle 11g. I am passing the table name as parameter through ASP.net using c#. But while running the application i am getting the error "ORA-00923: FROM keyword not found where expected error in oracle".
PROCEDURE "ARCHIVE_FILTERDATA" ( ITYPE IN VARCHAR2, itableName IN VARCHAR2, cur_archive OUT sys_refcursor ) AS
stmt clob;
endstmt clob;
BEGIN
IF ITYPE='Week'
THEN stmt := 'DELETE FROM '|| itableName ||' WHERE CREATEDATE < (SELECT DATE_ADD(CURDATE(), INTERVAL , - 1, WEEK))';
EXECUTE IMMEDIATE stmt;
END IF;
END;
So anybody have a solution please let me know ASAP. Thanks in Advance
You have three errors in your DELETE statement:
there is no date_add() function in Oracle (See the manual for a list of available functions)
there is no curdate() function in Oracle (See the manual for a list of available functions)
The sub-query is totally unnecessary. Plus: a select requires a from clause.
Putting it all together, your delete should look like this:
stmt := 'DELETE FROM '|| itableName ||' WHERE CREATEDATE < sysdate - interval ''1'' week';
(Note the duplicated single quotes inside the string literal).
Be aware that Oracle's DATE datatype always contains a time part. So sysdate - interval '1' week will return the date one week ago a the "current time". If you mean to include the complete day last week, you need to "remove" the time part by using trunc: trunc(sysdate) - interval '1' week.
You inner query will look alike:-
SELECT DATE_ADD(CURDATE(), INTERVAL , - 1, WEEK) FROM DUAL;
So plz correct your query.
I have a select statement which needs to select dozens of column into self-defined variable in my pl/sql. Like as below:
select col1,
col2,
....
col30
into var1,
...
var30
from table
where ....
While executing the SP I encounter the error:
ORA-06502: PL/SQL: numeric or value error: character string buffer too
small
The error information only points out the first line number of select statement. Even if i can figure out that my defined variable is too small to hold the column, it still makes me hard to locate the error-defined variable precisely. This is not an efficient way for me to debug this sp.
Is there any better idea, please advise me.
Two options are typically used in pl/sql:
1.Define your variables in PL/SQL to match the table's definition, using %type.
define
v_col1 my_table.col1%type;
v_col2 my_table.col2%type;
begin
select col1,col2
into v_col1, v_col2
from my_table
-- some condition that pulls 1 row
where rownum = 1;
end;
2.Define a row variable, using %rowtype
define
v_my_table_row my_table%rowtype;
begin
select *
into v_my_table_row
from my_table
where rownum = 1;
end;