Oracle Apex Email Validation to accept single user mail id - oracle

I have an item to enter the email id "item_email"
I need to give validation for email id item "item_email" that it should not accept more than one email ids.
Is there is any possible to do this, please help me to proceed on this.

A simple validation; count number of #s. For example:
SQL> with test as
2 (select 'lf#gmail.com' email from dual union
3 select 'lf#gmail.com bf#gmail.com' from dual
4 )
5 select regexp_count(email, '#') cnt
6 from test;
CNT
----------
1
2
SQL>
If such a query returns 1, item contains one "e-mail" address.
However, consider yet another validation - whether value entered into that item really looks like an e-mail. Because, if someone enters only "#", that would pass the previous validation, but it certainly isn't a valid e-mail address.
On the other hand, maybe you already perform that validation. In that case, disregard that objection.
[EDITED by LF, after reading OP's comment]:
Create a validation on the e-mail item (whose name is, for example, :P3_E_MAIL). Its type should be "PL/SQL function (returning error text)", and its code
if regexp_count(:P3_E_MAIL, '#') > 1 or
not regexp_like(:P3_E_MAIL, '^[a-zA-Z0-9._%-]+#[a-zA-Z0-9._%-]+\.[a-zA-Z]{2,4}$')
then
return ('E-mail address is incorrect');
end if;
See whether you're satisfied with such a code.

Related

Make a text field accept only numeric values in APEX

I have an APEX app that I am working on and need to make a field to only accept numeric values.
I want to have a validation that displays "Only numeric values allowed" whenever the user inputs letters or other characters that are not numeric.
How can I achieve this?
Thanks in advance
If you use the translate function, you can "detect" whether string contains something but digits (this example allows decimal dot as well):
SQL> with test (col) as
2 (select '1234' from dual union all -- valid
3 select '12a4' from dual union all -- invalid
4 select '12.4' from dual union all -- valid
5 select 'abcd' from dual union all -- invalid
6 select '1#34' from dual -- invalid
7 )
8 select col, translate(col, 'x0123456789.', 'x') result
9 from test;
COL RESU
---- ----
1234
12a4 a
12.4
abcd abcd
1#34 #
SQL>
So, if the result is NULL, then it is a valid value.
In Apex, you'd create validation (function that returns error text) which looks like this:
if translate(:P1_ITEM, 'x0123456789.', 'x') is not null then
return 'Only numeric values allowed';
else
return null;
end;
These field definitions are more about the inherent server-side validations that will run on your behalf to ensure the data submitted is numeric.
I think the best you're going to get is having some client side validation as well that gives the user immediate feedback - either has message, or auto-strip. I'm not sure if you can force a HTML element to only allow numerics.
If you really need to validate after each new character, you can try to add Dynamic Action based on Key Release event and Execute JavaScript code when true. Something like this
if ( $v("P2_NEW") !== ""
&& isNaN($v("P2_NEW"))) {
alert("Not a number");
}
Ok after some hours of trying this and that, the following is what has worked for me.
Click in the page. In the "Function and Global Variable Declaration" section add this code:
function isInputNumber(evt){
var ch = String.fromCharCode(evt.which);
if(!(/[0-9]/.test(ch))){
evt.preventDefault();
}
}
In the "Page HTML Body Attribute" section add this code:
onkeypress="isInputNumber(event)"
and thats it. This will prevent the user from entering letters into the input field.

Function to get the value from a key value pair by using the key when the key value pairs are stored in a single column

Imagine I had a table with the following structure in Oracle database.
ID Name Attributes
1 Rooney <Foot=left>, <height=5>, <country=England>
2 Ronaldo <Foot=Right>, <height=6>, <country=Portugal>
I want to create a function in which can return the value of a specific attribute when I pass in the ID, Name and Key of the attribute I need. Is that possible.
The query inside the function I was trying to use to determine the foot of the player Rooney is something like this.
SELECT Attributes
AS tmpVar
FROM Players
WHERE id = 1 AND Name = 'Rooney' and Attributes like '%Foot%';
Obviously it will give all the attributes but I just want his foot attribute. This is my first question here so please excuse If I made any novice mistakes and advice on how to ask better questions.
you may use REGEXP_SUBSTR
(.+?) captures the value, using non-greedy match, retrieved as 1 (last argument)
select REGEXP_SUBSTR(Attributes,'<Foot=(.+?)>',1,1,NULL,1) as Foot
FROM Players
Demo
You could parametrize that, such as
SQL> with players (id, name, attributes) as
2 (select 1, 'Rooney', '<Foot=left>, <height=5>, <country=England>' from dual union
3 select 2, 'Ronaldo', '<Foot=Right>, <height=6>, <country=Portugal>' from dual
4 )
5 select name,
6 replace(regexp_substr(attributes, '&&attribute=\w+'), '&&attribute=') result
7 from players
8 where id = 1;
Enter value for attribute: Foot
NAME RESULT
---------- --------------------
Rooney left
SQL> undefine attribute
SQL> /
Enter value for attribute: country
NAME RESULT
---------- --------------------
Rooney England
SQL>

SQL%FOUND where SELECT query returns no rows

I have the following function, which returns the next available client ID from the Client table:
CREATE OR REPLACE FUNCTION getNextClientID RETURN INT AS
ctr INT;
BEGIN
SELECT MAX(NUM) INTO ctr FROM Client;
IF SQL%NOTFOUND THEN
RETURN 1;
ELSIF SQL%FOUND THEN
-- RETURN SQL%ROWCOUNT;
RAISE_APPLICATION_ERROR(-20010, 'ROWS FOUND!');
-- RETURN ctr + 1;
END IF;
END;
But when calling this function,
BEGIN
DBMS_OUTPUT.PUT_LINE(getNextClientID());
END;
I get the following result:
which I found a bit odd, since the Client table contains no data:
Also, if I comment out RAISE_APPLICATION_ERROR(-20010, 'ROWS FOUND!'); & log the value of SQL%ROWCOUNT to the console, I get 1 as a result.
On the other hand, when changing
SELECT MAX(NUM) INTO ctr FROM Client;
to
SELECT NUM INTO ctr FROM Client;
The execution went as expected. What is the reason behind this behavior ?
Aggregate functions will always return a result:
All aggregate functions except COUNT(*), GROUPING, and GROUPING_ID
ignore nulls. You can use the NVL function in the argument to an
aggregate function to substitute a value for a null. COUNT and
REGR_COUNT never return null, but return either a number or zero. For
all the remaining aggregate functions, if the data set contains no
rows, or contains only rows with nulls as arguments to the aggregate
function, then the function returns null.
You can change your query to:
SELECT COALESCE(MAX(num), 1) INTO ctr FROM Client;
and remove the conditionals altogether. Be careful about concurrency issues though if you do not use SELECT FOR UPDATE.
Query with any aggregate function and without GROUP BY clause always returns 1 row. If you want no_data_found exception on empty table, add GROUP BY clause or remove max:
SQL> create table t (id number, client_id number);
Table created.
SQL> select nvl(max(id), 0) from t;
NVL(MAX(ID),0)
--------------
0
SQL> select nvl(max(id), 0) from t group by client_id;
no rows selected
Usually queries like yours (with max and without group by) are used to avoid no_data_found.
Agregate functions like MAX will always return a row. It will return one row with a null value if no row is found.
By the way SELECT NUM INTO ctr FROM Client; will raise an exception where there's more than one row in the table.
You should instead check whether or not ctr is null.
Others have already explained the reason why your code isn't "working", so I'm not going to be doing that.
You seem to be instituting an identity column of some description yourself, probably in order to support a surrogate key. Doing this yourself is dangerous and could cause large issues in your application.
You don't need to implement identity columns yourself. From Oracle 12c onwards Oracle has native support for identity columns, these are implemented using sequences, which are available in 12c and previous versions.
A sequence is a database object that is guaranteed to provide a new, unique, number when called, no matter the number of concurrent sessions requesting values. Your current approach is extremely vulnerable to collision when used by multiple sessions. Imagine 2 sessions simultaneously finding the largest value in the table; they then both add one to this value and try to write this new value back. Only one can be correct.
See How to create id with AUTO_INCREMENT on Oracle?
Basically, if you use a sequence then you don't need any of this code.
As a secondary note your statement at the top is incorrect:
I have the following function, which returns the next available client ID from the Client table
Your function returns the maximum ID + 1. If there's a gap in the IDs, i.e. 1, 2, 3, 5 then the "missing" number (4 in this case) will not be returned. A gap can occur for any number of reasons (deletion of a row for example) and does not have a negative impact on your database in any way at all - don't worry about them.

previous row oracle in cursor

I'm here because i could not finde anywhere else if there is a way to return the previous value in a loop (Cursor) to compare with the current value, for instance..
Cursor.Value = Cursor-1.Value;
It's bacause i have several contract numbers that i need to send by mail to the Business sector, but, in order to resume all the rows i want to compare if the current contract number are the same as the last contract number and validate it to dont send duplicated contract numbers.
Exemple of Record that i to skip in order to send no duplicate "Order Numbers": (Order_Number is my Key, not a sequencial numeric id):
cCursor.Value = cCursor-1.Value
cCursor.(111) = cCursor-1.(111)
Exemple of Record that i want to save in order to send as a processed "Order Number": (Order_Number is my Key, not a sequencial numeric id):
cCursor.Value = cCursor-1.Value
cCursor.(132) = cCursor-1.(111)
My Regards.
You cant reference backwards. Th easiest alternative is to store the key value (contract_id) in a variable and have logic like:
DECLARE
CURSOR c1 IS .....;
vLastContractID NUMBER := 0;
BEGIN
FOR r1 IN c1 LOOP
IF vLastContractID != r1.CONTRACT_ID THEN
-- do something
vLastContractID := r1.CONTRACT_ID;
END IF;
END LOOP;
END;
It's not entirely clear what you are asking.
A cursor is a forward-only structure. You cannot fetch a prior row, just the next row (or set of rows). Your query, however, can certainly include data from prior rows using the lag function. For example, this will show you the ename for the prior row in your result
SELECT empno, ename, lag(ename) over (order by empno) prior_ename
FROM emp
ORDER BY empno
In a PL/SQL loop, you can also obviously have a local variable that has the data from the previous row that was fetched and use that to compare against the data from the most current row.
Please use ANALYTICAL function to check for prior or post rows. LEAD,LAG functions are best way to do this.

Changing a 0 or 1 value to "Yes" and "No" in APEX report

I have a report region on my page and it's getting data from a students table. Within that table, there's a column called cv_lodged which is either 1 or 0 representing Yes or No. In the report it shows this columns data as 0 or 1, I want to change it to show Yes or No.
How can I do this?
You can put a CASE statement in your query
SELECT (CASE WHEN cv_lodged = 1
THEN 'Yes'
ELSE 'No'
END) cv_lodged,
other_columns
FROM students
If this is something that is likely to be common, you're probably better served creating a function that converts your pseudo-boolean data to a string. Something like
CREATE FUNCTION my_bool_to_str( p_num IN NUMBER )
RETURN VARCHAR2
IS
BEGIN
IF( p_num = 1 )
THEN
RETURN 'Yes';
ELSE
RETURN 'No';
END IF;
END;
that you would call in your query
SELECT my_bool_to_str( cv_lodged ) cv_lodged,
other_columns
FROM students
I've usually just created a static LOV in Shared Components called YES1_NO0, with 2 entries: 'Yes' -> 1, 'No' -> 0.
In Interactive Reports you can then change these columns. To do this, edit the column of the IR. Change 'Display Type' to 'Display as Text (based on LOV, escape special characters)'. Then under 'List of Values' set 'Column Filter Type' to 'Use Named List of Values to Filter Exact Match' and select the named LOV.
But sure, you can totally do this in SQL.
Currently, there is a simpler way to do this.
First open the APEX page with the "Yes/No" item as developer and click on the item to open the page item settings.
Change the Settings value from Use component settings to Custom.
Afterwards change the Yes Value to 1 and the No Value to 0.
This solution has some advantages:
No need to decode the value 1 or 0 to Y or N (select decode(mycolumn, 1, 'Y', 'N') from mytable where id = 123;) or select case when ...
No need to decode the submitted value back to 1 or 0 from Y or N

Resources