Im trying to write a procedure that updates the domain of an email (example: converting Email123#gmail.com into Email123#hotmail.com when i pass 2 strings gmail.com and hotmail.com) while having a cursor in my procedure
create of replace procedure pr_update_email
(Old_Email Varchar2, New_Email Varchar2)
As
V_OldDomain Varchar2(50);
Cursor C_Domains IS Select Email_Address
From Customer
where Email_Address Like '%#'||Old_Email;
Begin
Open C_Domains;
Fetch C_Domains INTO V_OldDomain;
While C_Domains %Found loop
Update Customer
Set Email_Address = regexp_replace(Email_Address, '^(.*#.*)'||Old_Email||'\1'||New_Email)
WHERE Email_Address LIKE V_OldDomain;
Fetch C_Domains into New_Email;
End Loop;
Close C_Domains;
End pr_update_email;
/
Show Errors;
getting errors:
19/11 PL/SQL: SQL Statement ignored
19/32 PLS-00403: expression'NEW_EMAIL' cannot be used as an INTO-target of a
SELECT/FETCH statement
You can directly update without creating a Stored Procedure but by using Regexp_Replace() and Instr() Functions :
SQL> Update Customer
Set Email_Address = Regexp_Replace(Email_Address,'(.*)#[gmail]+.(.*)','\1#hotmail.\2')
Where Instr(Email_Address,'#gmail.') > 0;
SQL> Commit;
If you want to create a generic structure in order to be able to use for such other cases also, then transfer the above Update statement as :
SQL> Create Or Replace Procedure pr_update_email(Old_Email Varchar2, New_Email Varchar2) As
Begin
Update Customer
Set Email_Address = Regexp_Replace(Email_Address,'(.*)#['||Old_Email||']+.(.*)','\1#'||New_Email||'.\2')
Where Instr(Email_Address,'#'||Old_Email||'.')>0 ;
End;
/
SQL> Begin
pr_update_email('gmail','hotmail');
End;
/
SQL> Commit;
Why you are using the cursor? It can be handled using simple update statement.
Your procedure should look like this:
create procedure pr_update_email (p_oldemail in varchar2,
p_newemail in varchar2)
As
Begin
UPDATE BROKER
SET
EMAIL_ADDRESS = REPLACE(EMAIL_ADDRESS, p_oldemail, p_newemail)
WHERE
REGEXP_LIKE ( EMAIL_ADDRESS,'.*#'|| p_oldemail|| '$' );
Commit;
End;
/
Or if you really want to use the loop then
create of replace procedure pr_update_email
(Old_Email Varchar2, New_Email Varchar2)
As
Begin
For i in (Select Email_Address
From Customer
where Email_Address Like '%#'||Old_Email) loop
Update Customer
Set Email_Address = Replace(Email_Address, old_email, new_email)
WHERE Email_Address = i.Email_Address;
End Loop;
Commit;
End pr_update_email;
/
To call this procedure, you need to pass both the domain as following:
Begin
pr_update_email('gmail.com', 'hotmail.com');
End;
/
And Yes, Issue in your code is following line:
Fetch C_Domains into New_Email;
New_Email is an input parameter and you can not assign any value to the input parameter.
Cheers!!
Related
I am querying APEX_COLLECTION view to see if a record exists and when it does not, I am getting NO_DATA_FOUND exception. To handle that I used an anonymous block:
BEGIN
SELECT c001, c002 INTO l_var1, l_var2
FROM APEX_COLLECTION
WHERE collection_name = 'TEST' AND c003='test';
EXCEPTION
WHEN NO_DATA_FOUND
l_var1 := NULL;
l_var2 := NULL;
END;
Is there a better way to handle this?
If you just want to see if a record exists, you can use de COUNT() function. In this way, it is not necessary to use anonymous blocks or NO_DATA_FOUND excepcion. The COUNT function always returns a value.
SELECT COUNT(*)
INTO l_count
FROM APEX_COLLECTION
WHERE collection_name = 'TEST' AND c003='test';
IF l_count > 0 THEN
-- Do something, the record exits
ELSE
-- Do something, the record does not exit
END IF;
Did not find better solution to my issue besides using anonymous block and capturing a NO_DATA_FOUND exception.
Use a predefined cursor and you won't be bothered with the NO_DATA_FOUND exception.
DECLARE
cursor c_apex_coll
is
SELECT c001, c002
FROM APEX_COLLECTION
WHERE collection_name = 'TEST' AND c003='test';
l_var1 varchar2(256);
l_var2 varchar2(256);
BEGIN
open c_apex_coll;
fetch c_apex_coll into l_var1, l_var2;
close c_apex_coll;
END;
I have PL/SQL anonymous block to work with finding an employees based on their department_id. I wrote a procedure for that.
Code
CREATE OR REPLACE PROCEDURE find_employees (
p_dept_no IN NUMBER,
p_error_message OUT VARCHAR2)
AS
v_dept_no NUMBER;
dept_chk EXCEPTION;
CURSOR find_emp
IS
SELECT employee_id,
first_name,
last_name,
salary,
hire_date
FROM employees
WHERE department_id = p_dept_no;
BEGIN
-- Check if the department_id in departments table
IF Condition
THEN --Need to check the condition here
RAISE dept_chk;
END IF;
FOR i IN find_emp
LOOP
DBMS_OUTPUT.put_line (i.employee_id);
DBMS_OUTPUT.put_line (i.first_name);
DBMS_OUTPUT.put_line (i.last_name);
DBMS_OUTPUT.put_line (i.salary);
DBMS_OUTPUT.put_line (i.hire_date);
END LOOP;
EXCEPTION
WHEN dept_chk
THEN
p_error_message := 'Please enter valid department number';
END find_employees;
How to check if the department_id in departments table
Note:
On that procedure there is one input parameter p_dept_no as INPUT
and p_error_message is the output parameter.
I need to check the if the department_id is in in the departments table then automatically the records will show other wise it's showing an exception so there i need to check the condition how it's possible let me know Thanks in advance.
Given that you already scan the table, you can simply set a variable in within the loop and check its value outside.
For example:
CREATE OR REPLACE PROCEDURE find_employees(p_dept_no IN
NUMBER,p_error_message OUT VARCHAR2)
AS
v_dept_no NUMBER;
dept_chk EXCEPTION;
vEmployeeFound boolean := false; -- a boolean variable
CURSOR find_emp
IS
SELECT
employee_id, first_name, last_name, salary, hire_date
FROM
employees
WHERE
department_id = p_dept_no;
BEGIN
FOR i in find_emp
LOOP
dbms_output.put_line(i.employee_id);
dbms_output.put_line(i.first_name);
dbms_output.put_line(i.last_name);
dbms_output.put_line(i.salary);
dbms_output.put_line(i.hire_date);
vEmployeeFound := true; -- set the variable
END LOOP;
-- Check if the department_id in departments table
IF NOT vEmployeeFound THEN -- check the variable value
RAISE dept_chk;
END IF;
EXCEPTION
WHEN dept_chk THEN
p_error_message:='Please enter valid department number';
END find_employees;
At opencart2.0, I want to create a ocmod extension, In install.sql, I need to modify the database field. When I modify the database field, I need to decide if the field exists. Ive tried multiple variations of this, but none of them seem to work. Any ideas? Thanks in advance.
this is my install.sql,but is error
DROP PROCEDURE IF EXISTS add_col_need_credit;
DELIMITER $$ CREATE PROCEDURE add_col_need_credit() BEGIN IF NOT EXISTS(SELECT column_name FROM information_schema.columns WHERE table_name='oc_customer_group_description' AND column_name='need_credit' ) THEN ALTER TABLE `oc_customer_group_description` ADD `need_credit` numeric(10,4) NOT NULL default 0; END IF;END$$ DELIMITER ;
CALL add_col_need_credit();
this is not error,you can in mysql console use it
DROP PROCEDURE IF EXISTS add_col_need_credit;
DELIMITER $$ CREATE PROCEDURE add_col_need_credit() BEGIN IF NOT EXISTS(SELECT column_name FROM information_schema.columns WHERE table_name='oc_customer_group_description' AND column_name='need_credit' ) THEN ALTER TABLE `oc_customer_group_description` ADD `need_credit` numeric(10,4) NOT NULL default 0; END IF;END$$ DELIMITER ;
CALL add_col_need_credit();
DROP PROCEDURE IF EXISTS add_col_need_credit;
DELIMITER $$ CREATE PROCEDURE add_col_need_credit() BEGIN IF NOT EXISTS(SELECT column_name FROM information_schema.columns WHERE table_name='oc_customer_group_description' AND column_name='need_credit' ) THEN ALTER TABLE `oc_customer_group_description` ADD `need_credit` numeric(10,4) NOT NULL default 0; END IF;END$$ DELIMITER ;
CALL add_col_need_credit();
I want to write a custom login and for that I want to use a procedure/function to create and login the user (to hash the password)
My current database setup looks like this (From this site: https://oracle-base.com/articles/9i/storing-passwords-in-the-database-9i):
CREATE TABLE app_users (
id NUMBER(10) NOT NULL,
username VARCHAR2(30) NOT NULL,
password VARCHAR2(40) NOT NULL
)
/
ALTER TABLE app_users ADD (
CONSTRAINT app_users_pk PRIMARY KEY (id)
)
/
ALTER TABLE app_users ADD (
CONSTRAINT app_users_uk UNIQUE (username)
)
/
CREATE SEQUENCE app_users_seq
/
My current PLSQL Package definition looks like this:
CREATE OR REPLACE PACKAGE app_user_security AS
FUNCTION get_hash (p_username IN VARCHAR2,
p_password IN VARCHAR2)
RETURN VARCHAR2;
PROCEDURE add_user (p_username IN VARCHAR2,
p_password IN VARCHAR2);
PROCEDURE change_password (p_username IN VARCHAR2,
p_old_password IN VARCHAR2,
p_new_password IN VARCHAR2);
PROCEDURE valid_user (p_username IN VARCHAR2,
p_password IN VARCHAR2);
FUNCTION valid_user (p_username IN VARCHAR2,
p_password IN VARCHAR2)
RETURN BOOLEAN;
END;
/
And the package itself looks like this:
CREATE OR REPLACE PACKAGE BODY app_user_security AS
FUNCTION get_hash (p_username IN VARCHAR2,
p_password IN VARCHAR2)
RETURN VARCHAR2 AS
l_salt VARCHAR2(30) := 'PutYourSaltHere';
BEGIN
-- Pre Oracle 10g
RETURN DBMS_OBFUSCATION_TOOLKIT.MD5(
input_string => UPPER(p_username) || l_salt || UPPER(p_password));
-- Oracle 10g+ : Requires EXECUTE on DBMS_CRYPTO
--RETURN DBMS_CRYPTO.HASH(UTL_RAW.CAST_TO_RAW(UPPER(p_username) || l_salt || UPPER(p_password)),DBMS_CRYPTO.HASH_SH1);
END;
PROCEDURE add_user (p_username IN VARCHAR2,
p_password IN VARCHAR2) AS
BEGIN
INSERT INTO app_users (
id,
username,
password
)
VALUES (
app_users_seq.NEXTVAL,
UPPER(p_username),
get_hash(p_username, p_password)
);
COMMIT;
END;
PROCEDURE change_password (p_username IN VARCHAR2,
p_old_password IN VARCHAR2,
p_new_password IN VARCHAR2) AS
v_rowid ROWID;
BEGIN
SELECT rowid
INTO v_rowid
FROM app_users
WHERE username = UPPER(p_username)
AND password = get_hash(p_username, p_old_password)
FOR UPDATE;
UPDATE app_users
SET password = get_hash(p_username, p_new_password)
WHERE rowid = v_rowid;
COMMIT;
EXCEPTION
WHEN NO_DATA_FOUND THEN
RAISE_APPLICATION_ERROR(-20000, 'Invalid username/password.');
END;
PROCEDURE valid_user (p_username IN VARCHAR2,
p_password IN VARCHAR2) AS
v_dummy VARCHAR2(1);
BEGIN
SELECT '1'
INTO v_dummy
FROM app_users
WHERE username = UPPER(p_username)
AND password = get_hash(p_username, p_password);
EXCEPTION
WHEN NO_DATA_FOUND THEN
RAISE_APPLICATION_ERROR(-20000, 'Invalid username/password.');
END;
FUNCTION valid_user (p_username IN VARCHAR2,
p_password IN VARCHAR2)
RETURN BOOLEAN AS
BEGIN
valid_user(p_username, p_password);
RETURN TRUE;
EXCEPTION
WHEN OTHERS THEN
RETURN FALSE;
END;
END;
/
I can call it like this in the CMD:
exec app_user_security.add_user('admin','admin');
But if I want to create a user in APEX > SQL Workshop > SQL Commands, it just tells me
ORA-00900: invalid SQL statement
Why is that so and how can I fix this? I want to use this login later on a application with a custom login scheme so it would be nice if there were some users in there.
Please try to run below code under APEX > SQL Workshop > SQL Commands
BEGIN
app_user_security.add_user('admin','admin');
END;
To know more about sql command under Sql workshop please check below link
https://docs.oracle.com/cd/E37097_01/doc.42/e35128/GUID-AF7DD819-A3E4-4027-84B7-4AEAD16314B7.htm#AEUTL219
Hope this will help you!
I have written a substring regular expression in Oracle. I am having a problem with the correct pattern matching. The substring query first fetches the ddl of the trigger into a string and then tries to separate the table's columns from it.
Trigger DDL
CREATE OR REPLACE TRIGGER "SHIVAMG"."DVJ_CI_CURRENCY_CD_L_IU"
BEFORE INSERT OR UPDATE ON CI_CURRENCY_CD_L
FOR EACH ROW
BEGIN
IF INSERTING THEN
IF (UPPER(:NEW.CURRENCY_CD) NOT LIKE 'ZZ%') THEN
INSERT INTO JUNITUSR.CI_CURRENCY_CD_L
(CURRENCY_CD,
LANGUAGE_CD,
DESCR,
VERSION)
SELECT :NEW.CURRENCY_CD,
:NEW.LANGUAGE_CD,
:NEW.DESCR,
:NEW.VERSION
FROM DUAL
WHERE NOT EXISTS
(SELECT 1
FROM JUNITUSR.CI_CURRENCY_CD_L B
WHERE B.CURRENCY_CD =:NEW.CURRENCY_CD AND
B.LANGUAGE_CD = :NEW.LANGUAGE_CD);
END IF;
END IF;
IF UPDATING THEN
IF (UPPER(:NEW.CURRENCY_CD) NOT LIKE 'ZZ%') THEN
UPDATE JUNITUSR.CI_CURRENCY_CD_L A
SET CURRENCY_CD =:NEW.CURRENCY_CD,
LANGUAGE_CD =:NEW.LANGUAGE_CD,
DESCR =:NEW.DESCR ,
VERSION =:NEW.VERSION
WHERE A.CURRENCY_CD = :OLD.CURRENCY_CD AND
A.LANGUAGE_CD =:OLD.LANGUAGE_CD;
END IF;
END IF;
EXCEPTION
WHEN OTHERS THEN
RAISE_APPLICATION_ERROR(-20001,'ERROR: <DVJ_CI_CURRENCY_CD_L_IU> ' || SQLERRM);
END;
ALTER TRIGGER "SHIVAMG"."DVJ_CI_CURRENCY_CD_L_IU" ENABLE"
Substring Query
SELECT REGEXP_SUBSTR((SELECT REGEXP_SUBSTR
(( select dbms_metadata.get_ddl('TRIGGER', 'DVJ_CI_CURRENCY_CD_L_IU' ) from dual), 'INSERT INTO(.*)+\)')FROM dual),'\((.*)\)') FROM DUAL;
I found the correct Substring query to gather the individual column names from the trigger code. It is as follows:
SELECT REGEXP_SUBSTR((SELECT REGEXP_SUBSTR((SELECT REGEXP_SUBSTR (( SELECT dbms_metadata.get_ddl( 'TRIGGER',trig_name,'CISADM') FROM dual),
'INSERT(\s|\n)+INTO[^\)]+\)',1,1,'n') FROM dual),'[\(](\s|\n|.)+[\)]')
FROM DUAL),'(\w)+',1,counter)INTO temp_col_name FROM dual;