I have a table containing house numbers as varchar2 like 10, 10a etc. I want to detect all the rows that are not numeric like ’10a’.
My solution would be to output every row that causes exception when there is an attempt to convert data like ’10a’ to number.
declare
number_correct number;
number_incorrect varchar2(4000);
begin
for rec in(select '10' house_nr from dual union select '10a' house_nr from dual)
loop
number_correct:=to_number(rec.house_nr);
number_incorrect:=rec.house_nr;
end loop;
exception
when others then
dbms_output.put_line('correct: '||number_correct);
dbms_output.put_line('incorrect: '||number_incorrect);
end;
It should show that incorrect is 10a, but it doesn’t.
While @Dave is right about the actual question you asked, I think what you’re trying to achieve is different than what you’re doing. As written the PL/SQL block will only evaluate values until it gets to the first non-number. If you want all values evaluated, then you’ll need something like this:
By moving the exception handling to inside the loop, we can continue processing after an error is raised. Also, this version only returns the “incorrect” message if the error that occurs is in fact a conversion error, as opposed to an unexpected error. When you’re writing error handling for specific conditions like this, it’s important to be as precise as possible.
As @Stephen points out, regex is generally faster than PL/SQL procedures or functions and a single SQL statement is typically better than a procedural loop. However, regex functions can only be used in
whereclauses, so if you want to see results for all values, you’d need to query your table twice:If you’re not comfortable with regex, or can’t come up with a suitable expression, you can still do this in a single SQL statement by creating your own function:
This won’t be quite as fast as using regex in most circumstances, but it does have one advantage: function-based indexes are notoriously finicky about regexp functions, but they shouldn’t have any problem with a function like this. It doesn’t seem like you’ll need an index for this particular query, but it’s something to keep in mind.