Oracle stored procedure - oracle

Can anyone help me by telling me what is wrong with the following syntax? I am just trying to run a simple SELECT statement in a stored procedure.
CREATE OR REPLACE PROCEDURE PVSSRDB.GETBATTERYSTATUSFORALLLOGGERS
(
p_Logger OUT e.comment_,
p_tStamp OUT h.ts,
p_Val OUT h.value_number
)
AS
BEGIN
select
e.comment_,
max(h.ts),
avg(h.value_number)
INTO
p_Logger,
p_tStamp,
p_Val
FROM
PVSSRDB.ELEMENTS e inner join PVSSRDB.DB15MINHISTORY_00100009 h on h.element_id =e.element_id
WHERE
e.element_name like 'System1:H%.BatteryCondition'
GROUP BY
e.comment_
ORDER by 2 asc
END GETBATTERYSTATUSFORALLLOGGERS;
I keep getting the same 3 errors stating:
Error(9,3): PL/SQL: SQL Statement Ignored
Error(23,18): PL/SQL: ORA_00933: SQL command not properly ended
Error(24,34): 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

You're missing a semicolon after the ORDER BY 2 asc
Also you need to declare your OUT parameters properly.
CREATE OR REPLACE
PROCEDURE PVSSRDB.GETBATTERYSTATUSFORALLLOGGERS (
p_Logger OUT PVSSRDB.ELEMENTS.comment_%TYPE,
p_tStamp OUT PVSSRDB.DB15MINHISTORY_00100009.ts%TYPE,
p_Val OUT PVSSRDB.DB15MINHISTORY_00100009.value_number%TYPE
)
AS
BEGIN
select e.comment_,
max(h.ts),
avg(h.value_number)
INTO p_Logger,
p_tStamp,
p_Val
FROM PVSSRDB.ELEMENTS e
inner join PVSSRDB.DB15MINHISTORY_00100009 h on (h.element_id =e.element_id)
WHERE e.element_name like 'System1:H%.BatteryCondition'
GROUP BY e.comment_
ORDER by 2 asc;
END GETBATTERYSTATUSFORALLLOGGERS;

Related

Errors when I create Oracle cursor

I am new to Oracle programming (started a month ago).
I've created a cursor to retrieve a value from a table 'CDF_LU' and then use the cursor to insert into another table 'test_1'. However there is an error when I run it.
Here is my code:
DECLARE
c_cdf_table CDF_LU.PROD_COLUMN_NAME%type;
-- create cursor.
CURSOR c_CDF_Table_Name IS
SELECT PROD_COLUMN_NAME
FROM CDF_LU
ORDER BY CDF;
-- create record.
c_cdf_table c_CDF_Table_Name%ROWTYPE;
BEGIN
OPEN c_CDF_Table_Name;
LOOP
FETCH c_CDF_Table_Name INTO c_cdf_table;
EXIT WHEN c_CDF_Table_Name%NOTFOUND;
-- insert to table_1.
INSERT into test_1
select A,B,C from table_1 where some_conditions
END LOOP;
CLOSE c_CDF_Table_Name;
END;
When I run this code, there are following errors:
In line 'FETCH c_CDF_Table_Name INTO c_cdf_table;', SQL statement ignored.
In line 'FETCH c_CDF_Table_Name INTO c_cdf_table;', at most one declaration for "C_CDF_TABLE" is permitted.
In line 'INSERT into test_1', SQL statement ignored.
I wrote the SQL codes above by strictly following the syntax of cursors, so I'm not sure where the problem is.
Could you please advise? Thank you!
The way you wanted to do it is possible (of course) when errors are fixed; something like this:
declare
-- cursor
cursor c_cdf_table_name is
select prod_column_name
from cdf_lu
order by cdf;
-- cursor variable
c_cdf_table c_cdf_table_name%rowtype;
begin
open c_cdf_table_name;
loop
fetch c_cdf_table_name into c_cdf_table;
exit when c_cdf_table_name%notfound;
insert into test1 (col1, col2, co3)
select a, b, c from table1
where d = c_cdf_table.prod_column_name;
end loop;
close c_cdf_table_name;
end;
/
However, there's a way shorter & simpler option - a cursor FOR loop. As you can see, you don't have to declare a cursor variable, open the cursor, fetch from it, take care about exiting the loop nor closing the cursor - Oracle does all that for you:
begin
for cur_r in (select prod_column_name
from cdf_lu
order by cdf)
loop
insert into test1 (col1, col2, co3)
select a, b, c from table1
where d = c_cdf_table.prod_column_name;
end loop;
end;
/

PL/SQL: I get the error "Encountered the symbol "FOR" when expecting one of the following: . ( * # % & - + /"

My code:
create table dep_emp_ast(
cod_dep number(3),
cod_ang number(3));
declare
type tab_imb is table of dept_ast.department_id%type;
t tab_imb:=tab_imb();
v_ang emp_ast.employee_id%type;
begin
select distinct department_id
bulk collect into t
from dept_ast;
forall i in 1..t.count
for j in (select employee_id
from emp_ast
where department_id=t(i)) loop
insert into dep_emp_ast
values(t(i),j.employee_id);
exit when sql%notfound;
dbms_output.put_line('Au fost introdusi '||sql%bulk_rowcount(i));
end loop;
end;
/
Apparently I cannot have the for statement inside the forall statement, but I need the forall statement so that I can use the sql%bulk_collect so that I can print the number of rows inserted. How do I solve this right? Basically I saved all the department_ids in a nested table and with the for statement I get all the employees for each department and insert the employee id along with the department id in my dep_emp_ast table.
I also get the error
Encountered the symbol "end-of-file" when expecting one of the following: end not pragma final instantiable order overriding static member constructor map
You'll have to switch from FORALL to FOR.
Or, simplify code and avoid inner loop entirely as it doesn't do anything smart; yes, you'll lose DBMS_OUTPUT.PUT_LINE call, but it is pretty much useless anywhere but in tools that support it. End users won't ever see it (in their e.g. Apex or Forms or ... applications).
So:
begin
select distinct department_id
bulk collect into t
from dept_ast;
forall i in 1..t.count
insert into dep_emp_ast
select a.department_id,
a.employee_id
from emp_ast a
where a.department_id = t(i);
end;

I have problem compile trigger using merge

can You explain me, where I did mistake in my code ?
CREATE OR REPLACE TRIGGER mda_01.tr_01_t01003 AFTER
INSERT ON mda_01.t01004_bo_semafor_log
FOR EACH ROW
DECLARE
PRAGMA autonomous_transaction;
BEGIN
IF inserting THEN
MERGE INTO mda_01.t01003_bo_semafor a
USING (
SELECT
:new.semafor_name,
:new.semafor_ts,
:new.semafor_status,
:new.semafor_desc
FROM
dual
) b
ON ( b.semafor_name = a.semafor_name )
WHEN MATCHED THEN UPDATE
SET a.semafor_ts = b.semafor_ts,
a.semafor_status = b.semafor_status
WHEN NOT MATCHED THEN
INSERT (
semafor_name,
semafor_ts,
semafor_status,
semafor_desc )
VALUES
( b.semafor_name,
b.semafor_ts,
b.semafor_status,
b.semafor_desc );
END IF;
COMMIT;
END;
/
I get an error:
LINE/COL ERROR
5/6 PL/SQL: SQL Statement ignored
16/8 PL/SQL: ORA-00904: "B"."SEMAFOR_NAME": invalid identifier
Errors: check compiler log
Thanks, Paul
I solved the problem.
I added aliases, and trigger was compiled with no errors:
SELECT
:new.semafor_name as semafor_name,
:new.semafor_ts as semafor_ts,
:new.semafor_status as semafor_status,
:new.semafor_desc as semafor_desc
FROM
dual

I am getting an error message in Oracle SQL stored procedure

I am trying the following code
CREATE OR REPLACE PROCEDURE sal2
AS
BEGIN
SELECT sal
FROM emp
END
And I'm getting this error
Error at line 7: 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
5. from emp
6. return 1
7. END
What I want to do is to get a sal column from emp table.
There are multiple issues with code as following;
create or replace procedure sal2
AS
Lv_var number; -- added variable for holding select value
BEGIN
select sal
Into lv_var -- into is needed in select
from emp; -- you missed this semicolon
-- you must use where clause as into variable can hold single value
-- so you must restrict this query to return only 1 record.
END; -- you missed this semicolon
/
Cheers!!
First you have to put the semicolon at the end of each line and after the END keyword. Then the SELECT statement is also wrong you have to load the result in a variable.
Here is the solution for multiple rows.
CREATE OR REPLACE PROCEDURE sal2
AS
CURSOR c_salaries IS SELECT salary FROM employees;
TYPE t_salaries IS TABLE OF c_salaries%rowtype INDEX BY BINARY_INTEGER;
v_salaries t_salaries;
BEGIN
OPEN c_salaries;
FETCH c_salaries BULK COLLECT INTO v_salaries;
CLOSE c_salaries;
END;
And one for a single row result.
CREATE OR REPLACE PROCEDURE sal2
AS
v_salary employees.salary%rowtype;
BEGIN
SELECT salary INTO v_salary
FROM employees WHERE employee_id = 100;
END;

ORA-22905 - While using DBMS_SQL.Number_Table for Table Operator

All,
Here is a simplified version of what I am attempting to accomplish. Instead of declaring my own type, I used the Number_Table type from the dbms_sql package.
First I created a simple test table:
CREATE TABLE collect_test(id NUMBER(38), other_info VARCHAR2(5));
Then, populated the table with a small amount of data:
INSERT INTO collect_test
SELECT rownum, chr(rownum+60)
FROM dual
CONNECT BY rownum <= 10;
Finally, I attempt to use PL/SQL to select some rows into a collection then use that collection to delete rows from the table:
DECLARE
l_tIDList DBMS_SQL.Number_Table;
BEGIN
SELECT ct.id
BULK COLLECT INTO l_tIDList
FROM collect_test ct
WHERE mod(ct.id, 2) = 0;
DELETE FROM (SELECT ct.id
FROM collect_test ct
INNER JOIN table(l_tIDList) ids ON ct.id = ids.column_value);
ROLLBACK;
END;
/
However, when I run this PL/SQL block I receive these errors:
ORA-06550: line 11, column 33:
PLS-00382: expression is of wrong type
ORA-06550: line 11, column 27:
PL/SQL: ORA-22905: cannot access rows from a non-nested table item
ORA-06550: line 9, column 3: PL/SQL: SQL Statement ignored
In all the other questions/articles I have found it seems like the coder was either trying to use a local type or forgetting to BULK COLLECT. I appreciate any suggestions you may have.
N.B.: I realize that I can do this specific functionality using a single DELETE statement. My actual scenario is more complicated and can't be done with a single statement.
Although it is not clear what you are trying to accomplish, there are two things which are wrong with your pl/sql block.
You can use the TABLE() function on the variables of collection
types defined in the schema and not on those defined locally
The way you are running your DML ( delete ) statement is wrong, it throws the error `
ORA-22841: DML on PL/SQL collections not supported.
So, create a collection TYPE in your schema and declare a collection of that type in your PL/SQL block and for your delete use an IN condition
CREATE OR REPLACE TYPE idlisttable as TABLE OF NUMBER;
DECLARE l_tidlist idlisttable;
BEGIN
SELECT ct.id BULK collect
INTO l_tidlist
FROM collect_test ct
WHERE MOD(ct.id, 2) = 0;
DELETE
FROM collect_test ct
WHERE ct.id IN (
SELECT ids.column_value
FROM TABLE (l_tidlist) ids
);
ROLLBACK;
END;
/
`
I have tried this using a cursor and it worked for me. Please try as below.
DECLARE
l_tIDList DBMS_SQL.Number_Table;
CURSOR c
IS
SELECT ct.id FROM collect_test ct WHERE mod(ct.id, 2) = 0;
BEGIN
OPEN c;
LOOP
FETCH c bulk collect INTO l_tIDList;
forall i IN 1 .. l_tIDList.count
DELETE FROM collect_test t WHERE t.id = l_tIDList(i);
EXIT
WHEN c%notfound;
END LOOP;
COMMIT;
CLOSE c;
END ;
/

Resources