i am trying to execute or run the following pl/sql script:
SET serveroutput on;
CREATE OR REPLACE PROCEDURE findAvg
(p_category IN products.category_id% TYPE, c OUT NUMBER)
AS
BEGIN
SELECT NVL ((SELECT AVG(LIST_PRICE) FROM products
WHERE p_category = category_id), -1) into p_category
from dual;
END findAvg;
DECLARE
cat products.category_id%TYPE;
Price products.List_price%TYPE;
BEGIN
cat := &p_category;
findAvg (cat, price);
if (price = -1) then
dbms_output.put_line('Wrong Category ');
ELSE
dbms_output.put_line('the average price for category' || cat || ' is ' || price);
END IF;
END;
/
show errors
but when i try to run it, i get this error message (i can see it only after show errors):
PLS-00103: Encountered the symbol "DECLARE"
what is wrong with this declare?
You are missing a "/" between the creation of the procedure and the start of the anonymous block that runs it:
SET serveroutput on;
CREATE OR REPLACE PROCEDURE findAvg
(p_category IN products.category_id% TYPE, c OUT NUMBER)
AS
BEGIN
SELECT NVL(AVG(LIST_PRICE),-1)
INTO c
FROM products
WHERE p_category = category_id;
END findAvg;
/
show errors
DECLARE
cat products.category_id%TYPE;
Price products.List_price%TYPE;
BEGIN
cat := &p_category;
findAvg (cat, price);
if (price = -1) then
dbms_output.put_line('Wrong Category ');
ELSE
dbms_output.put_line('the average price for category' || cat || ' is ' || price);
END IF;
END;
/
Also, the "show errors" command should be run just after creating the procedure, as I have above, and the INTO clause should specify the OUT parameter.
Related
I have error master table which contain description like 'Error in table abc in xyz column.' I need to format string for column name which is xyz here. Where ever I need to call this table I will pass column name and then I will get expected description.
Ex - Insert into errorTabl values(01,There is error in {0})
Whenever inside package I need to retrieve value of 01 then I will pass column name col1 so then expected value will be as below :
01 There is error in col1
Request you to please help me for insert and select both statements.
Though this doesn't make sense, maybe the code below could help you to start with something or to clarify your problem.
NOTE: the code below is here just to show you the basics - there is no sense in it for any kind of production. You are the one to adjust it to your context.
So, the package to put and get things into or from errors table:
CREATE OR REPLACE PACKAGE ERRS AS
Procedure putError(p_table IN VarChar2, p_column IN VarChar2);
Function getError(p_table VarChar2, p_column VarChar2) RETURN VarChar2;
END ERRS;
-- ---------------------------------------------------------------------------------
CREATE OR REPLACE PACKAGE BODY ERRS AS
Procedure putError(p_table IN VarChar2, p_column IN VarChar2) AS
BEGIN
Declare
mSql VarChar2(512) := '';
sq VarChar2(1) := '''';
Begin
mSql := 'Insert Into ERRORTABLE values( ' || sq || '01' || sq || ', ' || sq ||
'There is error in table ' || p_table || ' in ' || p_column || ' column' || sq || ')';
Execute Immediate mSql;
Commit;
End;
END putError;
-- -------------------------------------------------------------------------------
Function getError(p_table VarChar2, p_column VarChar2) RETURN VarChar2 IS
BEGIN
Declare
Cursor c IS
Select ERR_DESC From ERRORTABLE Where ERR_DESC Like('%table ' || p_table || ' in ' || p_column || '%');
mRet VarChar2(512) := '';
mDesc VarChar2(512) := '';
Begin
Open c;
LOOP
FETCH c into mDesc;
EXIT WHEN c%NOTFOUND;
mRet := '01 ' || mDesc || Chr(10);
END LOOP;
Close c;
RETURN RTRIM(mRet, Chr(10));
End;
END getError;
END ERRS;
Now the calling code to insert 5 records (once more - this is senseless) and to get you one of them...
set serveroutput on
DECLARE
errMsg VarChar2(512);
BEGIN
ERRS.putError('T_ABC', 'C_XYZ');
ERRS.putError('T_ABC', 'C_MNO');
ERRS.putError('T_ABC', 'C_PQR');
ERRS.putError('T_DEF', 'C_MNO');
ERRS.putError('T_DEF', 'C_XYZ');
--
errMsg := ERRS.getError('T_ABC', 'C_XYZ');
dbms_output.put_line(errMsg);
END;
/* R e s u l t :
anonymous block completed
01There is error in table T_ABC in C_XYZ column
*/
Just needed to pass double colon in insert query so then it will take single colon in table.
Ex - Insert into errorTabl values(01,There is error in ''{0}'')
In table it will be look like
**Id** **Description**
01 There is error in'{0}'.
I'm an Oracle/PL/SQL Developer newbie, and I'm struggling to figure out how to see the output of this query:
DECLARE
ncount NUMBER;
vwhere VARCHAR2(1000) := '';
vselect VARCHAR2(1000) := ' select count(1) from ';
vsearchstr VARCHAR2(1000) := '1301 250 Sage Valley Road NW';
vline VARCHAR2(1000) := '';
istatus INTEGER;
BEGIN
DBMS_OUTPUT.ENABLE;
FOR k IN (SELECT a.table_name, a.column_name FROM user_tab_cols a WHERE a.data_type LIKE '%VARCHAR%')
LOOP
vwhere := ' where ' || k.column_name || ' = :vsearchstr ';
EXECUTE IMMEDIATE vselect || k.table_name || vwhere
INTO ncount
USING vsearchstr;
IF (ncount > 0)
THEN
dbms_output.put_line(k.column_name || ' ' || k.table_name);
ELSE
dbms_output.put_line('no output');
END IF;
END LOOP;
dbms_output.get_line(vline, istatus);
END;
I got this script from https://community.oracle.com/tech/developers/discussion/2572717/how-to-search-a-particular-string-in-whole-schema. It's supposed to find a string (vsearchstr) in the entire database. When I run this in PL/SQL Developer 14.0.6, it spits out no errors, says it took 0.172 seconds, but I don't see any output. I'm expecting the output to show under the Output tab:
I know the string '1301 250 Sage Valley Road NW' exists in the database so it should be finding it. Even if it doesn't, the ELSE block should be outputting 'no output'.
From what I understand, dbms_output.put_line() adds the given string to a buffer, and dbms_output.get_line() prints it to the output target (whatever it's set to). I understand that dbms_output needs to be enabled (hence the line DBMS_OUTPUT.ENABLE) and dbms_output.get_line() will only run after the BEGIN/END block it's in completes (I don't know if this means it has to be put outside the BEGIN/END block, but I couldn't avoid certain errors every time I did).
I've read through various stackoverflow posts about this issue, as well as a few external site:
https://docs.oracle.com/cd/F49540_01/DOC/server.815/a68001/dbms_out.htm#1000449
https://www.tutorialspoint.com/plsql/plsql_dbms_output.htm
...but nothing seems to be working.
How can I see the output, or if there's something wrong in the query above, can you tell what it is?
Thanks.
To enable output from DBMS_OUTPUT in PL/SQL Developer see this answer.
I'm looking for an alternative keyword to user_tab_cols for all schemas in the DB
Use ALL_TAB_COLS and catch the exceptions when you do not have enough privileges to read the table (and use quoted identifiers to match the case of user/table/column names):
DECLARE
found_row PLS_INTEGER;
vsearchstr VARCHAR2(1000) := '1301 250 Sage Valley Road NW';
BEGIN
FOR k IN (SELECT owner,
table_name,
column_name
FROM all_tab_cols t
WHERE data_type LIKE '%VARCHAR%'
-- Ignore columns that are too small
AND data_length >= LENGTH(vsearchstr)
-- Ignore all oracle maintained tables
-- Not supported on earlier Oracle versions
AND NOT EXISTS (
SELECT 1
FROM all_users u
WHERE t.owner = u.username
AND u.oracle_maintained = 'Y'
)
)
LOOP
DECLARE
invalid_privileges EXCEPTION;
PRAGMA EXCEPTION_INIT(invalid_privileges, -1031);
BEGIN
EXECUTE IMMEDIATE 'SELECT 1 FROM "' || k.owner || '"."' || k.table_name || '" WHERE "' || k.column_name || '" = :1 AND ROWNUM = 1'
INTO found_row
USING vsearchstr;
dbms_output.put_line('Found: ' || k.table_name || '.' || k.column_name);
EXCEPTION
WHEN invalid_privileges THEN
NULL;
WHEN NO_DATA_FOUND THEN
dbms_output.put_line('Not found: ' || k.table_name || '.' || k.column_name);
END;
END LOOP;
END;
/
I am attempting to compile a package body to test a procedure in the package and I keep getting the above error.
CREATE TABLE TempBicycle AS
SELECT * FROM bike_shop.bicycle;
CREATE OR REPLACE PACKAGE BIKESHOP AS
PROCEDURE EXTRACT_BICYCLES (output_type IN VARCHAR2);
PROCEDURE EXTRACT_CUSTOMERS;
FUNCTION CUSTOMER_BIKES RETURN BOOLEAN;
PROCEDURE ARCHIVE_CUSTOMER_BIKES;
count NUMBER(38,0);
CURSOR ext_bikes_cur IS
SELECT SerialNumber, ModelType, PaintID, FrameSize, OrderDate, StartDate, ShipDate, Construction, ListPrice,
SalePrice, SalesTax, SaleState
FROM TempBicycle
ORDER BY OrderDate ASC;
END BIKESHOP;
/
CREATE OR REPLACE PACKAGE BODY BIKESHOP AS
PROCEDURE EXTRACT_BICYCLES (output_type IN VARCHAR2) IS
BEGIN
IF output_type = 'D' THEN
count := 0;
FOR Bikes IN ext_bikes_cur LOOP
INSERT INTO bicycles
( SerialNumber, ModelType, PaintID, FrameSize, OrderDate, StartDate, ShipDate, Construction, ListPrice,
SalePrice, SalesTax, SaleState)
VALUES ( Bikes.SerialNumber, Bikes.ModelType, Bikes.PaintID, Bikes.FrameSize, Bikes.OrderDate, Bikes.StartDate,
Bikes.ShipDate, Bikes.Construction, Bikes.ListPrice, Bikes.SalePrice, Bikes.SalesTax, Bikes.SaleState);
count := count +1;
END LOOP;
DBMS_OUTPUT.PUT_LINE('Records Inputted: ' || count);
ELSE IF output_type = 'S' THEN
FOR Bikes IN ext_bikes_cur LOOP
DBMS_OUTPUT.PUT_LINE(chr(10) || '----------Bike Information----------');
DBMS_OUTPUT.PUT_LINE ('Serial Number: ' || Bikes.SerialNumber);
DBMS_OUTPUT.PUT_LINE ('Model: ' || Bikes.ModelType);
DBMS_OUTPUT.PUT_LINE ('Paint ID: ' || Bikes.PaintID);
DBMS_OUTPUT.PUT_LINE ('Frame: ' || Bikes.FrameSize);
DBMS_OUTPUT.PUT_LINE ('Date Ordered: ' || Bikes.OrderDate);
DBMS_OUTPUT.PUT_LINE ('Start Date: ' || Bikes.StartDate);
DBMS_OUTPUT.PUT_LINE ('Date Shipped: ' || Bikes.ShipDate);
DBMS_OUTPUT.PUT_LINE ('Construction: ' || Bikes.Construction);
DBMS_OUTPUT.PUT_LINE ('Listed Price: ' || Bikes.ListPrice);
DBMS_OUTPUT.PUT_LINE ('Sale Price: ' || Bikes.SalePrice);
DBMS_OUTPUT.PUT_LINE ('Sales Tax: ' || Bikes.SalesTax);
DBMS_OUTPUT.PUT_LINE ('State Sold: ' || Bikes.SaleState);
END LOOP;
ELSE
DBMS_OUTPUT.PUT_LINE('Incorrect Input');
END IF;
END;
PROCEDURE EXTRACT_CUSTOMERS IS
BEGIN
NULL;
END;
FUNCTION CUSTOMER_BIKES RETURN BOOLEAN IS
BEGIN
RETURN TRUE;
END;
PROCEDURE ARCHIVE_CUSTOMER_BIKES IS
BEGIN
NULL;
END;
END BIKESHOP;
/
BEGIN
BikeShop.ExtractBicyclesaz('S');
END
I am wanting the procedure to print out to the console the contents of the cursor if the procedure is passed an "S" and for it to input the cursor data if it is passed a "D"
Error(37,6): PLS-00103: Encountered the symbol ";" when expecting one of the following: if
PL/SQL uses ELSIF, not ELSE IF. Correct that in EXTRACT_BICYCLES and you should be good.
Well, actually ELSE IF is allowed, but it changes the structure of the statements. For example, what you're trying to do is
IF something THEN
ya_da;
ELSIF something_else THEN
ya_da_ya_da;
ELSE
the_other_thing;
END IF;
If you really wanted to use ELSE IF the code structure would become
IF something THEN
ya_da;
ELSE
IF something_else THEN
ya_da_ya_da;
ELSE
the_other_thing;
END IF;
END IF;
So you end up needing an END IF for the "outer" IF statement, and a second END IF for the "inner" IF statement.
Hi i'm a begginer in pl/sql under oracle. i'tried to write this pl/SQL programm but i had this error:
Encountered the symbol "WHILE" when expecting one of the following: . ( * # % & - + / at loop mod remainder rem ..'
SET SERVEROUTPUT ON
DECLARE
CURSOR EMP_CURSOR IS SELECT EMPLOYEE_NAME, SALARY, DATE_HIRE FROM EMPLOYEES WHERE DEPARTMENT_ID=1;
BEGIN
FOR EMP_REC IN EMP_CURSOR
WHILE EMP_REC%FOUND
LOOP
IF EMP_REC.SALARY > 10000 AND EMP_REC.DATE_HIRE< DATE '2000-01-01'
THEN
DBMS_OUTPUT.PUT_LINE (EMP_REC.EMPLOYEE_NAME || ' earns ' || EMP_REC.SALARY || 'and joined the organization on ' || EMP_REC.DATE_HIRE);
END IF;
END LOOP;
END LOOP;
END;
/
SET SERVEROUTPUT OFF
Try this:
DECLARE
CURSOR EMP_CURSOR IS SELECT EMPLOYEE_NAME, SALARY, DATE_HIRE FROM EMPLOYEES WHERE DEPARTMENT_ID=1;
BEGIN
FOR EMP_REC IN EMP_CURSOR
LOOP
IF EMP_REC.SALARY > 10000 AND EMP_REC.DATE_HIRE< DATE '2000-01-01'
THEN
DBMS_OUTPUT.PUT_LINE (EMP_REC.EMPLOYEE_NAME || ' earns ' || EMP_REC.SALARY || 'and joined the organization on ' || EMP_REC.DATE_HIRE);
END IF;
END LOOP;
END;
I have this query and it's not updating into the database. The given "where" clause is valid. When I run the query independently, it works fine but in this Procedure it's not working. There is no exception or no error. Could you guys help me in figuring out where the problem is?
EXECUTE IMMEDIATE 'UPDATE ' || dest || ' SET COUNTRY_CODE = :v1 WHERE col_id = :v2'
USING l_vc_CountryCode, l_vc_ColId;
if SQL%ROWCOUNT > 1 THEN
inserts := inserts + 1;
counter := counter + 1;
IF counter > 500 THEN
counter := 0;
COMMIT;
END IF;
END IF;
I didn't write the commit code before. Just to clarity.
I suppose that col_id is the primary key. So in the update statement
EXECUTE IMMEDIATE 'UPDATE ' || dest || ' SET COUNTRY_CODE = :v1 WHERE col_id = :v2'
USING l_vc_CountryCode, l_vc_ColId;
you are always updating at most one row and thus the condition
SQL%ROWCOUNT > 1
is never true ( 1 is not > 1 )
So if you don't have any other commit statement in your procedure, you will never commit those updates.
By the way: what is the purpose of this
if SQL%ROWCOUNT > 1 THEN
inserts := inserts + 1;
counter := counter + 1;
IF counter > 500 THEN
counter := 0;
COMMIT;
END IF;
END IF;
why don't you just commit at the end of your work?
The following code works okay (ie updates the row).
I suspect your error is elsewhere.
For example, if you don't initialise COUNTER, the increment will still leave it as null and it will never commit.
Or, l_vc_ColId may be the wrong datatype and suffering from an invalid conversion.
declare
v_emp_id number := 7839;
v_name varchar2(4) := 'DING';
v_tab varchar2(3) := 'EMP';
begin
execute immediate 'update '||v_tab||
' set ename = :v_name Where empno = :v_emp_id'
using v_name, v_emp_id;
dbms_output.put_line('C:'||sql%rowcount);
end;
you may want to reconsider your design if your using dynamic sql to change the "dest" table in thousands of updates.
Much better to know your dest and use bind variables for the where conditions. then you can commit every x rows using mod or similar:
if (mod(v_ctr, 1000) = 0) then
commit;
end if;
But for your example, Marcin is correct, if you are updating only 1 row at a time, then
if SQL%ROWCOUNT > 1
will never be true;
EDIT:
A simple example knowing your "dest" table:
declare
cursor sel_cur is
select col1, col2, from sourceTable where col3 = 'X';
v_ctr pls_integer := 0;
begin
for rec in sel_cur
loop
v_ctr := v_ctr + 1;
-- implicit bind variables used
update destTable
set col1 = rec.col1,
col2 = rec.col2
where col3 = 'Z';
if (mod(v_ctr, 1000) = 0) then
commit;
end if;
end loop;
exception
when others then rollback;
raise;
end;
If using dynamic SQL, a simple example using explicit bind variables (USING clause) from Oracle docs:
CREATE OR REPLACE PROCEDURE raise_emp_salary (column_value NUMBER,
emp_column VARCHAR2, amount NUMBER) IS
v_column VARCHAR2(30);
sql_stmt VARCHAR2(200);
BEGIN
-- determine if a valid column name has been given as input
SELECT COLUMN_NAME INTO v_column FROM USER_TAB_COLS
WHERE TABLE_NAME = 'EMPLOYEES' AND COLUMN_NAME = emp_column;
sql_stmt := 'UPDATE employees SET salary = salary + :1 WHERE '
|| v_column || ' = :2';
EXECUTE IMMEDIATE sql_stmt USING amount, column_value;
IF SQL%ROWCOUNT > 0 THEN
DBMS_OUTPUT.PUT_LINE('Salaries have been updated for: ' || emp_column
|| ' = ' || column_value);
END IF;
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE ('Invalid Column: ' || emp_column);
END raise_emp_salary;
/
For more reading, see here.
Hope this helps, happy coding
Execute immediate needs explicit commit. I guess you checked that ?