I have an Apex application text item to enter the email ids with comma separator.
Now I want to validate the email address whether it's correct or not which entered in application item.
How to achieve this?
I am using the below code but its not working.
declare
l_cnt varchar2(1000);
l_requestors_name varchar2(4000);
begin
select apex_item.text(1) Member
into l_requestors_name
from dual;
if not l_requestors_name not like '%#%' then
return true;
else
return false;
end if;
end;
I'd suggest you to create a function which returns a Boolean or - as in my example - a character (Y - yes, it is valid; N - no, it isn't valid) (why character? You can use such a function in SQL. Boolean works in PL/SQL, but my example is pure SQL).
I guess it isn't perfect, but should be way better than just testing whether a string someone entered contains a monkey (#).
SQL> create or replace
2 function f_email_valid (par_email in varchar2)
3 return varchar2
4 is
5 begin
6 return
7 case when regexp_substr (
8 par_email,
9 '[a-zA-Z0-9._%-]+#[a-zA-Z0-9._%-]+\.[a-zA-Z]{2,4}')
10 is not null
11 or par_email is null then 'Y'
12 else 'N'
13 end;
14 end f_email_valid;
15 /
Function created.
SQL>
As user can enter several e-mail addresses separated by a comma, you'll have to split them into rows and then check each of them. Have a look:
SQL> with test (text) as
2 -- sample data
3 (select 'littlefoot#gmail.com,bigfootyahoo.com,a##hotmail.com,b123#freemail.hr' from dual),
4 split_emails as
5 -- split that long comma-separated values column into rows
6 (select regexp_substr(text, '[^,]+', 1, level) email
7 from test
8 connect by level <= regexp_count(text, ',') + 1
9 )
10 -- check every e-mail
11 select email, f_email_valid(email) is_valid
12 from split_emails;
EMAIL IS_VALID
------------------------------ --------------------
littlefoot#gmail.com Y
bigfootyahoo.com N
a##hotmail.com N
b123#freemail.hr Y
SQL>
Related
I want to use the ORACLE DBMS_SCHEDULER on my AWS RDS ORACLE
https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Appendix.Oracle.CommonDBATasks.Scheduler.html
to do the following command every minute:
delete from MYTABLE.RECEIVED_TOKEN where EXPIRY_DATE < systimestamp and rownum <= 1;
commit;
exit
can I do that with this scheduler? I want to avoid the possibility to use a Lambda if it is possible.
I donĀ“t understand too much about how it works or if I can schedule something like that.
I don't know AWS.
As this is an Oracle database, use its scheduling capabilities. How? "Convert" that delete statement into a stored procedure which will then be scheduled by (older and somewhat simpler) DBMS_JOB or (modern, improved and more complex) DBMS_SCHEDULER package.
Here's example.
Procedure:
SQL> CREATE OR REPLACE PROCEDURE p_del_rt
2 IS
3 BEGIN
4 DELETE FROM received_token
5 WHERE expiry_date < SYSTIMESTAMP
6 AND ROWNUM <= 1;
7
8 COMMIT;
9 END;
10 /
Procedure created.
Daily job which runs at 02:00 (2 past midnight):
SQL> BEGIN
2 DBMS_SCHEDULER.CREATE_JOB (
3 job_name => 'delete_received_token',
4 job_type => 'PLSQL_BLOCK',
5 job_action => 'BEGIN p_del_rt; end;',
6 start_date =>
7 TO_TIMESTAMP_TZ ('10.01.2023 02:00 Europe/Zagreb',
8 'dd.mm.yyyy hh24:mi TZR'),
9 repeat_interval =>
10 'FREQ=DAILY; BYDAY=MON,TUE,WED,THU,FRI,SAT,SUN; BYHOUR=2; BYMINUTE=0',
11 enabled => TRUE,
12 comments => 'Delete rows whose expiry date is less than "right now"');
13 END;
14 /
PL/SQL procedure successfully completed.
What is it set to?
SQL> SELECT job_action,
2 TO_CHAR (next_run_date, 'dd.mm.yyyy hh24:mi:ss') next_run_date
3 FROM USER_SCHEDULER_JOBS
4 WHERE job_name = 'DELETE_RECEIVED_TOKEN';
JOB_ACTION NEXT_RUN_DATE
-------------------- -------------------
BEGIN p_del_rt; end; 11.02.2023 02:00:00
SQL>
So that we wouldn't wait until tomorrow, I'll run the job manually. This is table contents before (dates are in DD.MM.YYYY format) (today is 10.02.2023, which means that ID = 1 and ID = 2 have expiry_date less than today):
SQL> SELECT * FROM received_token;
ID EXPIRY_DATE
---------- ------------
1 23.12.2022
2 28.01.2023
3 13.08.2023
SQL> BEGIN
2 DBMS_SCHEDULER.run_job ('delete_received_token');
3 END;
4 /
PL/SQL procedure successfully completed.
Table contents after:
SQL> SELECT * FROM received_token;
ID EXPIRY_DATE
---------- ------------
2 28.01.2023
3 13.08.2023
SQL>
Apparently, it works. Though, I'm not sure what you meant to say by using the following condition:
and rownum <= 1
Why do you want to restrict number of rows deleted to (at most) one? (it'll be zero if no row's expiry_date is less than systimestamp). Without that condition, both ID = 1 and ID = 2 rows would have been deleted.
No problem with me, just saying.
I can't see my error. Could you show me where I am going wrong?
CREATE OR REPLACE TRIGGER update_installments_info
AFTER INSERT OR UPDATE OF COLLECT_AMOUNT ON test_installments
FOR EACH ROW
DECLARE
v_id number;
BEGIN
UPDATE test_sales
SET REST_AMOUNT = REST_AMOUNT - :NEW.COLLECT_AMOUNT,
PAID_AMOUNT = PAID AMOUNT + :NEW.COLLECT_AMOUNT
WHERE SALES_ID = :NEW.SALES_ID;
END;
/
Error at line 4: PL/SQL: ORA-00933: SQL command not properly ended
Error is in UPDATEs 3rd line; cColumn name isn't PAID AMOUNT (with a space), but PAID_AMOUNT. Once fixed:
SQL> CREATE OR REPLACE TRIGGER update_installments_info
2 AFTER INSERT OR UPDATE OF COLLECT_AMOUNT ON test_installments
3 FOR EACH ROW
4 DECLARE
5 v_id number;
6 BEGIN
7 UPDATE test_sales
8 SET REST_AMOUNT = REST_AMOUNT - :NEW.COLLECT_AMOUNT,
9 PAID_AMOUNT = PAID_AMOUNT + :NEW.COLLECT_AMOUNT --> here
10 WHERE SALES_ID = :NEW.SALES_ID;
11 END;
12 /
Trigger created.
SQL>
I have 2 cols
SID CID
1 101,102
2 201,2021,231
IN TGT
SID CID
1 101
1 102
2 201
2 2021
2 231
You need to use normalizer.
First after SQ, use expression transformation to split CID column.
o_cid1= substr(cid,1,3) --if length is variable you need to use instr
o_cid2= substr(cid,instr(cid,',',1)+1, 3) -- if length is variable you need to use instr
...
Then use normalizer. Properties should be
Number of occurrences of sid =0
Number of occurrences of cid =3
You will see 4input ports(3for for cid1,2,3 and 1for sid) and two outports(1cid,1sid) related to your needs.
Conect sid, o_cid1,o_cid2... To corresponding ports.
Finally connect output ports cid,sid to target.
I've a varchar2 column in a table which contains a few entries like the following
TEMPORARY-2 TIME ECS BOUND -04-Insuficient Balance
I want to update these entries and make it TEMPORARY-2 X. What's the way out?
To accomplish this, you can either use character functions such as substr(),
replace()
or a regular expression function - regexp_replace() for instance.
SQL> with t1(col) as(
2 select 'TEMPORARY-2 TIME ECS BOUND -04-Insuficient Balance'
3 from dual
4 )
5 select concat(substr( col, 1, 11), ' X') as res_1
6 , regexp_replace(col, '^(\w+-\d+)(.*)', '\1 X') as res_2
7 from t1
8 ;
Result:
RES_1 RES_2
------------- -------------
TEMPORARY-2 X TEMPORARY-2 X
So your update statement may look like this:
update your_table t
set t.col_name = regexp_replace(col_name, '^(\w+-\d+)(.*)', '\1 X')
-- where clause if needed.
I want to extract text from a column using regular expressions in Oracle 11g. I have 2 queries that do the job but I'm looking for a (cleaner/nicer) way to do it. Maybe combining the queries into one or a new equivalent query. Here they are:
Query 1: identify rows that match a pattern:
select column1 from table1 where regexp_like(column1, pattern);
Query 2: extract all matched text from a matching row.
select regexp_substr(matching_row, pattern, 1, level)
from dual
connect by level < regexp_count(matching_row, pattern);
I use PL/SQL to glue these 2 queries together, but it's messy and clumsy. How can I combine them into 1 query. Thank you.
UPDATE: sample data for pattern 'BC':
row 1: ABCD
row 2: BCFBC
row 3: HIJ
row 4: GBC
Expected result is a table of 4 rows of 'BC'.
You can also do it in one query, functions/procedures/packages not required:
WITH t1 AS (
SELECT 'ABCD' c1 FROM dual
UNION
SELECT 'BCFBC' FROM dual
UNION
SELECT 'HIJ' FROM dual
UNION
SELECT 'GBC' FROM dual
)
SELECT c1, regexp_substr(c1, 'BC', 1, d.l, 'i') thePattern, d.l occurrence
FROM t1 CROSS JOIN (SELECT LEVEL l FROM dual CONNECT BY LEVEL < 200) d
WHERE regexp_like(c1,'BC','i')
AND d.l <= regexp_count(c1,'BC');
C1 THEPATTERN OCCURRENCE
----- -------------------- ----------
ABCD BC 1
BCFBC BC 1
BCFBC BC 2
GBC BC 1
SQL>
I've arbitrarily limited the number of occurrences to search for at 200, YMMV.
Actually there is an elegant way to do this in one query, if you do not mind to run some extra miles. Please note that this is just a sketch, I have not run it, you'll probably have to correct a few typos in it.
create or replace package yo_package is
type word_t is record (word varchar2(4000));
type words_t is table of word_t;
end;
/
create or replace package body yo_package is
function table_function(in_cur in sys_refcursor, pattern in varchar2)
return words_t
pipelined parallel_enable (partition in_cur by any)
is
next varchar2(4000);
match varchar2(4000);
word_rec word_t;
begin
word_rec.word = null;
loop
fetch in_cur into next;
exit when in_cur%notfound;
--this you inner loop where you loop through the matches within next
--you have to implement this
loop
--TODO get the next match from next
word_rec.word := match;
pipe row (word_rec);
end loop;
end loop;
end table_function;
end;
/
select *
from table(
yo_package.table_function(
cursor(
--this is your first select
select column1 from table1 where regexp_like(column1, pattern)
)
)