oracle explicit cursor loop - oracle

I want to replace the domain name using cursor without a loop, which is an explicit cursor. but I also want to changes all the same domain names in the database by given pass a string.
example: exec PR_Q3( 'usa.com','hotmail.com'); all the domain name with 'usa.com'in database will change to 'hotmail.com'.
create or replace procedure PR_Q3
(old_email in varchar2, new_email in varchar2)
authid current_user
is
cursor E_info is select Email_Address from broker
where REGEXP_LIKE (substr(Email_Address, instr(Email_Address,'#')+1), old_email);
v_email E_info%rowtype;
begin
open E_info;
loop
fetch E_info into v_email;
exit when E_info%notfound;
update broker set
Email_Address = replace(Email_Address,substr(Email_Address,instr(Email_Address,'#')+1),new_email)
where Email_Address = v_email.Email_Address;
end loop;
close E_info;
end PR_Q3;
it works if I delete the loop, but it only changes the domain name once.
I need changes all the same domain name.
I want to do the same thing without a loop. Can I?

You can use the following simple update in your procedure:
CREATE OR REPLACE PROCEDURE PR_Q3 (
OLD_EMAIL IN VARCHAR2,
NEW_EMAIL IN VARCHAR2
)
AUTHID CURRENT_USER
IS
BEGIN
UPDATE BROKER
SET
EMAIL_ADDRESS = REPLACE(EMAIL_ADDRESS, OLD_EMAIL, NEW_EMAIL)
WHERE
REGEXP_LIKE ( EMAIL_ADDRESS,
'.*#' || OLD_EMAIL || '$' );
COMMIT;
END PR_Q3;
/
Cheers!!

Related

Function works in PL/SQL but not in PowerBi

When I call the function, it works in SQL*Plus but doesn't work in PowerBI.
I opened PowerBI> Get Data> Oracle> Entered server name> Went to advanced options to enter sql below
SELECT * FROM TABLE(TESTPOWERBI);
Error: We encountered an error while trying to connect. SQL command not properly ended.
Anyone have experience in solving this?
DROP TYPE VW_PEOPLE_TABLE;
DROP TYPE VW_PEOPLE_TYPE;
CREATE OR REPLACE TYPE VW_PEOPLE_TYPE AS OBJECT(NAME VARCHAR2(70), ALIAS VARCHAR2(90));
/
CREATE OR REPLACE TYPE VW_PEOPLE_TABLE AS TABLE OF VW_PEOPLE_TYPEL
/
CREATE OR REPLACE FUNCTION TESTPOWERBI RETURN VW_PEOPLE_TABLE
PIPELINED
AUTHID CURRENT_USER
AS
VWT VW_PEOPLE_TABLE;
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
SELECT
VW_PEOPLE_TYPE(NAME, ALIAS)
BULK COLLECT
INTO VWT
FROM MYDATABASE;
FOR i in 1 .. VWT.COUNT
LOOP
PIPE ROW (VW_PEOPLE_TYPE(VWT(i).NAME, VWT(i).ALIAS));
END LOOP;
END TESTPOWERBI;
/
GRANT EXECUTE ON TESTPOWERBI TO PUBLIC;
You mixed your delimiters ; and /.
Clean it up and add one at the end behind GRANT EXECUTE ON TESTPOWERBI TO PUBLIC.
In addition you got a typo: for i in 1 .. vwt.count only two dots.
This should work:
DROP TYPE VW_PEOPLE_TABLE;
DROP TYPE VW_PEOPLE_TYPE;
CREATE OR REPLACE TYPE VW_PEOPLE_TYPE AS OBJECT
(
NAME VARCHAR2 (70),
ALIAS VARCHAR2 (90)
);
CREATE OR REPLACE TYPE VW_PEOPLE_TABLE AS TABLE OF VW_PEOPLE_TYPEL;
CREATE OR REPLACE FUNCTION TESTPOWERBI
RETURN VW_PEOPLE_TABLE
PIPELINED
AUTHID CURRENT_USER
AS
VWT VW_PEOPLE_TABLE;
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
SELECT VW_PEOPLE_TYPE (NAME, ALIAS)
BULK COLLECT INTO VWT
FROM MYDATABASE;
FOR i IN 1 .. VWT.COUNT
LOOP
PIPE ROW (VW_PEOPLE_TYPE (VWT (i).NAME, VWT (i).ALIAS));
END LOOP;
END TESTPOWERBI;
/
GRANT EXECUTE ON TESTPOWERBI TO PUBLIC;
Here some discussion about delimiters:
When do I need to use a semicolon vs a slash in Oracle SQL?

Error(4,5): PLS-00428: an INTO clause is expected in this SELECT statement

create or replace PROCEDURE find_Doctor (p_SSN in number) AS
BEGIN
select drName, drPhone
from clients
where SSN = p_SSN;
END find_Doctor;
I've got this stored procedure and I just want to output the resulting table from that call. Is there an easy way to do this without declaring a temporary table? I can't just make is a normal SQL query because I have to call it from a java program.
In a Procedure you would need variable to hold the result output of the SQL query. You can then use the variable. Use this:
CREATE OR REPLACE PROCEDURE find_Doctor (p_SSN IN NUMBER)
AS
var_nm VARCHAR2 (100);
var_ph NUMBER;
BEGIN
SELECT drName, drPhone
INTO var_nm, var_ph
FROM clients
WHERE SSN = p_SSN;
DBMS_OUTPUT.put_line ('Doc Name - ' || var_nm || 'Doc Ph. No-' || var_ph);
END find_Doctor;
Edit:
I can't just make is a normal SQL query because I have to call it from
a java program.
You can then use SYS_REFCUSOR to return results, which can be mapped to a JDBC ResultSet.
CREATE OR REPLACE PROCEDURE find_Doctor (p_SSN IN NUMBER,
VAR OUT SYS_REFCURSOR)
AS
BEGIN
OPEN VAR FOR
SELECT drName, drPhone
FROM clients
WHERE SSN = p_SSN;
END find_Doctor;
You should define out parameters drName and drPhone:
create or replace PROCEDURE find_Doctor (p_SSN in number, p_drName OUT
VARCHAR2, p_drPhone OUT VARCHAR2) AS
BEGIN
select drName, drPhone
into p_drName, p_drPhone
from clients
where SSN = p_SSN;
END find_Doctor;
Easy way is to learn tool you're used and best practices for it.
For me, best way is remove senseless procedure and just selects data you need. But if you adherent of 'SP only' approach you can use ref cursor to retrive required data:
create or replace function find_Doctor (p_SSN in number)
return sys_refcursor as
v_result sys_refcursor;
BEGIN
open v_result for
select drName, drPhone
from clients
where SSN = p_SSN;
return v_result;
END find_Doctor;

Output results from Oracle Ref cursor

How can i rewrite below pl/sql block in order to avoid hard code column names one by one ? Below data are from OE schema. For orders table there are 8 columns on this table. Is it possible to output the results without hard code column names ? Any help is appreciated.
create or replace PACKAGE show_details AS
TYPE rt_order IS REF CURSOR RETURN orders%ROWTYPE;
TYPE typ_cust_rec IS RECORD
(cust_id NUMBER(6), cust_name VARCHAR2(20),
custphone customers.phone_numbers%TYPE,
credit NUMBER(9,2), cust_email VARCHAR2(30));
TYPE rt_cust IS REF CURSOR RETURN typ_cust_rec;
--Get order detail
PROCEDURE get_order(p_orderid IN NUMBER, p_cv_order IN OUT rt_order);
--Get customer detail
PROCEDURE get_cust(p_custid IN NUMBER, p_cv_cust IN OUT rt_cust);
END show_details;
create or replace PACKAGE BODY show_details
AS
PROCEDURE get_order (p_orderid IN NUMBER, p_cv_order IN OUT rt_order)
IS
BEGIN
OPEN p_cv_order FOR
SELECT * FROM orders
WHERE order_id = p_orderid;
-- CLOSE p_cv_order
END get_order;
PROCEDURE get_cust (p_custid IN NUMBER, p_cv_cust IN OUT rt_cust)
IS
BEGIN
OPEN p_cv_cust FOR
SELECT customer_id, cust_first_name,phone_numbers,
credit_limit,cust_email FROM customers WHERE customer_id = p_custid;
-- CLOSE p_cv_cust
END get_cust;
END;
SET SERVEROUTPUT ON SIZE UNLIMITED;
declare
cur_orders show_details.rt_order;
v_ordertab cur_orders%ROWTYPE;
begin
show_details.get_order(p_orderid =>2397, p_cv_order =>cur_orders);
LOOP
FETCH cur_orders INTO v_ordertab;
EXIT WHEN cur_orders%NOTFOUND;
DBMS_OUTPUT.PUT_LINE('ORDER_ID: ' || v_ordertab.ORDER_ID || ' ORDER_DATE: ' || v_ordertab.ORDER_DATE || ' ORDER_MODE: ' || v_ordertab.ORDER_MODE || ' CUSTOMER_ID: ' || v_ordertab.CUSTOMER_ID);
END LOOP;
exception
when others then
DBMS_OUTPUT.put_line ('Error Code : ' || SQLCODE);
end;
/
Since you're executing this from SQL Developer, you can use the variable and print commands, which are carried over from SQL*Plus:
variable cur_orders refcursor;
exec show_details.get_order(p_orderid => 2397, p_cv_order => :cur_orders);
print cur_orders
CUR_ORDERS
-------------------------------------------------------------------------------------------------------------------------------------------------
ORDER_ID CUSTOMER_ID ORDER_MODE ORDER_DATE
--------------------------------------- --------------------------------------- --------------------------------------- -------------------------
2397 42 0 03-JAN-15
Notice that you're passing the ref cursor variable as a bind variable, so there is a colon before the name in the call (:cur_order). And you need to run script rather than run statement.
exec is just a shorthand for an anonymous block, so you could do it explicitly if you prefer, but the effect is the same:
var cur_orders refcursor;
begin
show_details.get_order(p_orderid => 2397, p_cv_order => :cur_orders);
end;
/
print cur_orders
You can also get the output in the result grid if you prefer, as shown here, but print is a bit closer to your dbms_output version. Or you can have a wrapper function so you could call query the procedure from a plain SQL call; depends what your end goal is, and if you're just manually executing the procedure to check the output then print may also be good enough.

How do i run the procedure

exec home_lending_cus('9999999999', 'HOME LENDING', '11111111')
I am trying to run the above statement but it is throwing a error mentioned below.
ORA-00933: SQL Command not properly ended.
ORA-06512: at 'HOME_LENDING_CUS', line 6
ORA-06512: at line1
All the variables of type varchar2
CREATE OR REPLACE PROCEDURE home_lending_cus(
id_no VARCHAR2,
prod_nme VARCHAR2,
rpt_dte NUMBER) authid current_user
AS
BEGIN
EXECUTE immediate
' CREATE TABLE abc AS
SELECT bt.id,
ct.cus_id
FROM bnkr_tbl bt ,
cus_tbl ct ,
base_tbl bt
WHERE bt.id =ct.id
AND ct.id =bt.c_id
AND bt.pr_nme='||prod_nme|| '
AND bt.dte ='||rpt_dte|| '
AND bt.id ='||id_no|| '
GROUP BY bt.id,
ct.cus_id';
END home_lending_cus;
As #Aramillo pointed out, the quotes around the string variables are wrong, which is making the dynamic SQL not work. However, I would strongly recommend shifting to bind variables, rather than concatenation. Not only will this prevent that kind of error, it will protect you from SQL injection:
CREATE OR REPLACE PROCEDURE home_lending_cus(
id_no VARCHAR2,
prod_nme VARCHAR2,
rpt_dte NUMBER) authid current_user
AS
BEGIN
EXECUTE immediate
' CREATE TABLE abc AS
SELECT bt.id,
ct.cus_id
FROM bnkr_tbl bt ,
cus_tbl ct ,
base_tbl bt
WHERE bt.id =ct.id
AND ct.id =bt.c_id
AND bt.pr_nme= :1
AND bt.dte = :2
AND bt.id = :3
GROUP BY bt.id,
ct.cus_id' using prod_nme, rpt_dte, id_no;
END home_lending_cus;
Or, rather, it would if you were allowed to use bind variables in DDL. Given that limitation, my inclination would be to split this into two commands.
CREATE OR REPLACE PROCEDURE home_lending_cus(
id_no VARCHAR2,
prod_nme VARCHAR2,
rpt_dte NUMBER) authid current_user
AS
BEGIN
EXECUTE immediate
' CREATE TABLE abc (bt_id number, cus_id number)'
EXECUTE IMMEDIATE
'INSERT INTO abc (bt_id, cus_id)
SELECT bt.id,
ct.cus_id
FROM bnkr_tbl bt ,
cus_tbl ct ,
base_tbl bt
WHERE bt.id =ct.id
AND ct.id =bt.c_id
AND bt.pr_nme= :1
AND bt.dte = :2
AND bt.id = :3
GROUP BY bt.id,
ct.cus_id' using prod_nme, rpt_dte, id_no;
END home_lending_cus;
There are a couple other issues with this code that you may want to consider:
Your query is also invalid because you're using the alias bt twice in the same FROM clause.
I'd recommend using SQL-99 style joins, rather than the comma-separated list of tables.
Oracle code that creates a table on the fly is always a little suspect. do you really need to create a table, or can you use a global temporary table? The latter is almost always going to be the better option.

How can implement a procedure in ESQL (an internal procedure) from Oracle database

I create a store procedure in Oracle db that insert Customer to my Table
this is my code :
CREATE OR REPLACE PROCEDURE THP.INSERT_CUSTOMER(
P_CUSTNAME IN VARCHAR2,
P_CUSTLAST IN VARCHAR2,
P_CUSTFATHER IN VARCHAR2,
P_NATIONNO IN NUMBER,
P_BIRTHDAY IN VARCHAR2,
P_BIRHTPLACE IN VARCHAR2,
P_EMAIL IN VARCHAR2,
P_CUSTENAME IN VARCHAR2,
P_CUSTELAST IN VARCHAR2,
P_OWNID IN NUMBER,
P_CUSTTYPEID IN NUMBER,
P_GENDERID IN NUMBER,
P_BILLSTID IN NUMBER,
P_BILLSPID IN NUMBER,
P_IDNO IN varchar2,
RESULT OUT INTEGER) IS
CNT NUMBER;
BEGIN
RESULT := 1;
CNT := 0;
SELECT COUNT(1) INTO CNT FROM THP.TBCUSTOMER WHERE NATIONNO=P_NATIONNO ;
IF CNT=1 THEN
COMMIT;
RESULT := 1; --IF RECORD is EXIST
ELSE
BEGIN
INSERT INTO TBCUSTOMER(CUSTID,CUSTNAME,CUSTLAST,CUSTFATHER,NATIONNO,BIRTHDAY,BIRHTPLACE,EMAIL,CUSTENAME,CUSTELAST,OWNID,CUSTTYPEID,GENDERID,BILLSTID,BILLSPID,IDNO)
VALUES(CUSTID_SEQ.NEXTVAL,P_CUSTNAME,P_CUSTLAST,P_CUSTFATHER,P_NATIONNO,P_BIRTHDAY,P_BIRHTPLACE,P_EMAIL,P_CUSTENAME,P_CUSTELAST,P_OWNID,P_CUSTTYPEID,P_GENDERID,P_BILLSTID,P_BILLSPID,P_IDNO);
COMMIT;
RESULT :=0; --IF INSERT NEW COLUMN
END;
END IF;
END INSERT_CUSTOMER;
/
now I want use this procedure in ESQL and create it directly in ESQL not CALL it from Oracle database or other DB
would you please guide me a bout it...
General comments, not an answer ...
count(1)
count(1) = count(*), which is the standard form for "count the number of rows". count(1) has no advantages, so best to use count(*).
RESULT := 1
is redundant at the beginning of the procedure
CNT := 0
... also redundant. The variable name is not very meaningful, and might make people think of a rude word, so perhaps change it to rows_found.
Prefixing the arguments with P_ is not required. If you use one of them in a SQL statement and need to deconflict it from a database object name then prefix it with the procedure name, so you have:
WHERE NATIONNO= INSERT_CUSTOMER.NATIONNO
Is NATIONNO constrained to be unique in the customer table? If not, use:
SELECT COUNT(*)
INTO CNT
FROM THP.TBCUSTOMER
WHERE NATIONNO=INSERT_CUSTOMER.NATIONNO AND
ROWNUM = 1;
(12g will introduce the LIMIT SQL syntax, by the way).
Commiting in a procedure is often held to be bad practice, as the procedure often becomes part of a longer business transaction (eg. inserting a new customer and address) and the commit should be controlled by the application code.
Upper case code is harder to read than lower case -- that's why direction signs on motorways are not uppercase.
The begin-end block for the insert is not required at all.
"birhtplace" is spelled wrong.
So I'd suggest that what you want to convert to ESQL is actually:
create or replace procedure thp.insert_customer(
custname in varchar2,
custlast in varchar2,
custfather in varchar2,
nationno in number ,
birthday in varchar2,
birhtplace in varchar2,
email in varchar2,
custename in varchar2,
custelast in varchar2,
ownid in number ,
custtypeid in number ,
genderid in number ,
billstid in number ,
billspid in number ,
idno in varchar2,
result out integer) is
rows_found number;
begin
select count(*)
into rows_found
from thp.tbcustomer
where nationno=insert_customer.nationno;
if rows_found = 1 then
result := 1;
else
insert into
tbcustomer(
custid ,
custname ,
custlast ,
custfather,
nationno ,
birthday ,
birthplace,
email ,
custename ,
custelast ,
ownid ,
custtypeid,
genderid ,
billstid ,
billspid ,
idno)
values(
custid_seq.nextval,
custname ,
custlast ,
custfather,
nationno ,
birthday ,
birthplace,
email ,
custename ,
custelast ,
ownid ,
custtypeid,
genderid ,
billstid ,
billspid ,
idno);
result :=0;
end if;
end insert_customer;
/
To call an external procedure via ESQL, you need to first declare the external function.
Do it as below:
CREATE PROCEDURE DoSomething (IN in1 CHARACTER, OUT out1 CHARACTER, OUT out2 CHARACTER)
LANGUAGE DATABASE
EXTERNAL NAME "DoSomething";
Now you can call this function from your ESQL function as below:
CALL DoSomething(in,out1,out2) IN Database.yourschema.yourDB;
P.S. The parameters you are passing must be compatible with the parameters of your stored procedure.

Resources