What does '[^~]+' do? - oracle

I am reviewing some code that was written before I got to my company and I see this '[^~]+' used in a lot of code. To add some context it is a part of a for loop function.
DECLARE
new_parent_id number;
BEGIN
FOR i IN (
select regexp_substr(:PAGE1_SELECTED, '[^~]+', 1, level) material_num, rownum
from dual
connect by regexp_substr(:PAGE1_SELECTED, '[^~]+', 1, level) is not NULL)
LOOP
if i.ROWNUM = 1 then
new_parent_id := ASSIGN_NEW_MATERIAL (
pMATERIAL_NUMBER => i.MATERIAL_NUMBER,
pASSEMBLY_NAME => :PAGE1_NEW_ASSEMBLY
);
else
ASSIGN_MATERIAL_TO_PARENT (
pNEW_PARENT_ID => new_parent_id,
pPART_NUMBER => i.PART_NUMBER
);
end if;
END LOOP;
END;

I'd expect that :PAGE1_SELECTED is a tilde-separated string of material_num values that this code is parsing. If you're looking at the values of the bind variables when this code is called to determine that there are no tildes, I'd go back to the application to see if there are different code paths that could produce lists of values.

Related

Flag duplicate characters in a string

I'm using oracle apex and i'm trying to write a pl/sql statement that will flag duplicates in a string. For example the string 'P,T,P,C' has two occurrences of the letter 'P' so it should raise an error. After all my digging the closest I got to achieving this was by using REGEXP_LIKE, but my regular expression skills are sub par. If anyone can assist that would be much appreciated.
DECLARE
v_seccode varchar2(10) := 'P,T,P,C';
BEGIN
if regexp_like(v_seccode, '(P{2,}?|C{2,}?|W{2,}?|T{2,}?)') then
raise_application_error(-20001,'You can not have the same SEC code listed more than once!');
end if;
END;
If your apex version is relatively recent you have access to the APEX_STRING API. Here is some code using that API, using same logic #Littlefoot showed in the other answer:
DECLARE
l_arr1 apex_t_varchar2;
l_arr2 apex_t_varchar2;
BEGIN
-- convert string to array with "," delimiter
l_arr1 := apex_string.split(:P1_SECCODE,',');
l_arr2 := l_arr1;
-- remove dupes from l_arr2
l_arr2 := l_arr2 MULTISET UNION DISTINCT l_arr2;
IF l_arr2 != l_arr1 THEN
return 'You can not have the same SEC code listed more than once!';
END IF;
END;
/
As you're using Apex, I suggest you create a validation within it. Code you posted suggests that you'd want to handle that elsewhere (process? Database trigger?).
Presuming that page item name is P1_SECCODE, validation - a PL/SQL function that returns error text - might look like this (read comments within code):
declare
l_seccode varchar2(20);
begin
-- Split P1_SECCODE into rows, fetch distinct values and aggregate them back.
-- If P1_SECCODE = 'P,T,P,C' then the L_SECCODE = 'P,T,C'
select listagg(distinct regexp_substr(:P1_SECCODE, '[^,]+', 1, level), ',')
within group (order by null)
into l_seccode
from dual
connect by level <= regexp_count(:P1_SECCODE, ',') + 1;
-- Now compare whether P1_SECCODE has the same number of commas as L_SECCODE.
-- If not, it means that P1_SECCODE contained duplicates so - return an error message
if regexp_count(:P1_SECCODE, ',') <> regexp_count(l_seccode, ',') then
return 'You can not have the same SEC code listed more than once!';
end if;
end;
If your database version doesn't support distinct within listagg, then first fetch distinct values and then aggregate them:
declare
l_seccode varchar2(20);
begin
-- Split P1_SECCODE into rows, fetch distinct values and aggregate them back.
-- If P1_SECCODE = 'P,T,P,C' then the L_SECCODE = 'P,T,C'
with temp as
(select distinct regexp_substr(:P1_SECCODE, '[^,]+', 1, level), ',') val
from dual
connect by level <= regexp_count(:P1_SECCODE, ',') + 1
)
select listagg(val, ',') within group (order by null)
into l_seccode
from temp;
-- Now compare whether P1_SECCODE has the same number of commas as L_SECCODE.
-- If not, it means that P1_SECCODE contained duplicates so - return an error message
if regexp_count(:P1_SECCODE, ',') <> regexp_count(l_seccode, ',') then
return 'You can not have the same SEC code listed more than once!';
end if;
end;
Given that your string can only have 4 possible letters PCWT, you could just use LIKE expressions along with a regular query:
SELECT *
FROM yourTable
WHERE string NOT LIKE '%P%P%' AND
string NOT LIKE '%C%C%' AND
string NOT LIKE '%W%W%' AND
string NOT LIKE '%T%T%';

I'm trying to get a process to be kicked off when a query finds a table is empty

I want to code a way to check if there's data in a table prior to executing a stored procedure.
I've created some 'stripped down' test code that 'almost' meets the conditions that I seek, I was hoping someone might be able to help me get that to work. If so, then I can substitute the values for my procedure, instead of just the dbms_output and be up and running.
Creates a test table, with no rows.
CREATE TABLE t (c VARCHAR2(20));
Then the way I am trying to do this...
declare
no_such_table exception;
pragma exception_init( no_such_table, -942 );
EXISTS_1 integer;
BEGIN
for tst in (
select count (c) x from t
)
loop
execute immediate' select count (c) Z from ' ||tst.t into EXISTS_1;
if EXISTS_1 <= 0
then
dbms_output.put_line( 'a' );
else dbms_output.put_line( 'b' );
end if;
end loop;
exception
when no_such_table
then
dbms_output.put_line( 'c' );
WHEN NO_DATA_FOUND THEN
dbms_output.put_line( 'd' );
end;
The first part, with the count, is supposed to hold a numeric value to indicate if there are any rows in the table. Then the execute immediate into EXISTS_1 holds the value to decide what output to give.
Firstly, I can't get the execute immediate bit to actually work. But if I could get it working, I want the output to record 'a' if there's no rows in the table. (Actually, I would execute the procedure here) and to record 'b' if there was data in there, which you can insert with:
insert into t (c) values('x');
commit;
The 'c' and 'd' outputs are just attempts to handle other potential issues that may occur.
As things stand, I get an error indicating that component t must be declared. Can you understand what I 'm trying to do, and if so, hopefully suggest a means to achieve my goal please?
your first select in a loop will always return one row, so there now Need to do a loop.
using tst.t in a Loop is not possible.
is that what are you looking for?
declare
x number := 0;
begin
select count(c) into x from t;
if x <= 0
then
dbms_output.put_line( 'a' );
else
dbms_output.put_line( 'b' );
end if;
end;

Not getting the desired results

enter code hereI have a Problem. Below pl/sql used to be working before and now i dont know whats happening... I want to insert records into a table called incoming from an interactive report using a check box
my sql is
SELECT apex_item.checkbox2(1,filenumber)
|| apex_item.hidden(2,filename)
|| APEX_ITEM.hidden(3,'&APP_USER. ')
|| APEX_ITEM.hidden(4,volume)
|| APEX_ITEM.hidden(6,filename)
as "SELECT",
FILENUMBER,
FILENAME,
LOCATION,
OPENDATE,
CLOSEDDATE,
VOLUME,
SUB,
temporary,
registryid,
STATUS
from REGISTRY
my pl/sql is
begin
for idx in 1 .. apex_application.g_f01.count
loop
if apex_application.g_f01(idx) is not null then
insert into incoming
(filenumber,
filename
)
values
(apex_application.g_f01(idx),
apex_application.g_f02(idx)
);
end if;
end loop;
end;
and all this happens after process..this was working fine.. However from recent the problem i am having is the pl/sql gives me the correct filenumber but the incorrect filename.
e.g
lets say the ir report has
filenumber filename
1 aaron
2 kerron
3 Joshua
when i select number 2 (second record) the result in the incoming table will be
filenumber filename
2 aaron
its always selecting the first record once it falls in the apex_item.hidden.
if i reverse it and put
SELECT apex_item.checkbox2(1,filename)
|| apex_item.hidden(2,filenumber)
the filename is correct and the file number will do what i explained above which is if i choose the second record i will get
filenumber filename
1 kerron
when i add
begin
for idx in 1 .. apex_application.g_f01.count loop
for i in 1..apex_application.g_f02.count loop
if apex_application.g_f01(idx) is not null then
insert into INCOMINGREQUESTNOTIFICATION
(requestedfile,filenumber
)
values
(apex_application.g_f01(idx),
apex_application.g_f02(i)
);
end if;
end loop;
end loop;
end;
#romeuBraga i am getting all 3 rows not the selected one can you tell me what am doing wrong
You need a hidden item to store the ID.
*1 and 2 store the same information
select column1,
column2,
column3,
apex_item.hidden(p_idx => 1,
p_value => code) ||
apex_item.checkbox2(p_idx => 2,
p_value => code) CheckBox,
other items
from x
in this case, you need this pl/sql to get the correct row values.
begin
for i in 1..apex_application.g_f01.count loop
for j in 1..apex_application.g_f02.count loop
if apex_application.g_f01(i) = apex_application.g_f02(j) then
--insert something here
end if;
end loop;
end loop;
end;

Building a table of numbers within a FOR LOOP

I have below procedure which I need to call from another procedure.
PROCEDURE get_list_ntds_for_given_port(
pis_olt_name IN common.types.string
, pis_chasis_lt_port IN common.types.string
, pona_ntd_ids OUT common_api.ntabtype
)
IS
lsa_object_name common_api.vtabtype;
lsa_link_type common_api.vtabtype;
lsa_link_status common_api.vtabtype;
lna_link_object_id common_api.ntabtype;
lsa_link_object_name common_api.vtabtype;
lsa_link_object_class common_api.vtabtype;
ln_pon_port_id NUMBER;
lna_child_pon_result FLS_NUMBER_TABLE;
lona_ntd_ids common_api.ntabtype;
ls_pon_port_map common.types.string;
BEGIN
ls_pon_port_map := pis_olt_name || '/' || pis_chasis_lt_port;
ln_pon_port_id := nwmdl.alu_pon_port.find(
pis_full_pon_port_name => ls_pon_port_map
);
lna_child_pon_result:= rm.sri_object_utils.get_child_objects(
pis_proc_name => lc_proc_name
, pin_parent_id => ln_pon_port_id
);
pona_ntd_ids := common_api.ntabtype();
FOR i IN 1..lna_child_pon_result.COUNT
LOOP
rm.ims_objects_api.get_peer_links (
pin_object_id => lna_child_pon_result(i)
, pis_geographical_only => 'N'
, pona_object_id => lona_ntd_ids
, posa_object_name => lsa_object_name
, posa_link_type => lsa_link_type
, posa_link_status => lsa_link_status
, pona_link_object_id => lna_link_object_id
, posa_link_object_name => lsa_link_object_name
, posa_link_object_class => lsa_link_object_class
);
pona_ntd_ids.EXTEND(lona_ntd_ids.COUNT);
FOR i IN 1..lona_ntd_ids.COUNT
LOOP
pona_ntd_ids(i) := lona_ntd_ids(i);
END LOOP;
END LOOP;
END get_list_ntds_for_given_port;
I simulate the external call with this pl-sql block:
SET SERVEROUTPUT ON;
DECLARE
lona_ntd_ids common_api.ntabtype;
BEGIN
svcmgr_lni.design_and_assign.get_list_ntds_for_given_port( pis_olt_name => 'SWOLT0000003DV'
,pis_chasis_lt_port => '1-1/LT1/1'
,pona_ntd_ids => lona_ntd_ids
);
FOR i IN 1..lona_ntd_ids.COUNT
LOOP
DBMS_OUTPUT.PUT_LINE(lona_ntd_ids(i));
END LOOP;
END;
The problem is that I don't get any result in the output.
My guess is that my rm.ims_objects_api.get_peer_links API will be called for every lna_child_pon_result(i) found by rm.sri_object_utils.get_child_objectsand will put in the OUT param of the API more exactly in every output parm a table of numbers(ids) or varchar.
What I want to achive is to build the table of numbers of the main PROCEDURE(get_list_ntds_for_given_port) and set it to the output parameter so to use that table of numbers outside the main procedure.
Please leave any ideas that you have on solving this.
Try this:
Move "pona_ntd_ids := common_api.ntabtype();" outside the loops:
pona_ntd_ids := common_api.ntabtype();
FOR i IN 1..lna_child_pon_result.COUNT
Change
pona_ntd_ids(i) := lona_ntd_ids(i);
to
pona_ntd_ids(pona_ntd_ids.COUNT+1) := lona_ntd_ids(i);
Since in your original code you initialize pona_ntd_ids for every loop you will end up with nothing if the last outer iteration yields lona_ntd_ids.COUNT=0.
Lilte modification you can do and bulk collect the whole object and then make it as OUT param. Yes this will be a overhead on program as Regex is used but it will suffice your query.
FOR i IN 1..lona_ntd_ids.COUNT
LOOP
lv_eg_string := lona_ntd_ids(i)||','||lv_eg_string;
-- pona_ntd_ids(i) := lona_ntd_ids(i);
END LOOP;
lv_eg_string:=substr(lv_eg_string,1,length(lv_eg_string)-1);
SELECT regexp_substr(lv_eg_string,'[^,]+', 1, level) BULK COLLECT
INTO pona_ntd_ids
FROM dual
CONNECT BY regexp_substr(lv_eg_string, '[^,]+', 1, level);

PLS-00231 for in procedure defined function

I looked up the problem but didn't find a solution. my problem is as follows
create or replace procedure GETINFO(
pIVR OUT NUMBER
) IS
FUNCTION IS_MASK_ALLOWED(
pBusSeg IN NUMBER,
pCHTPMask IN NUMBER
)
RETURN BOOLEAN
IS
BEGIN
IF pCHTPMask > 0 THEN
ELSE RETURN TRUE;
END IF;
END;
BEGIN
SELECT 1
INTO pIVR
FROM DUAL
WHERE IS_MASK_ALLOWED(1, 2)=TRUE;
END;
the compiler says that I can not use IS_MASK_ALLOWED in SQL statements
ORACLE 10g
PL/SQL developer 7.5
Oracle does not support boolean statements in SQL so using True will not work. Try select 1 from dual where True = True to confirm.
Secondly if you're not allowing anyone to access is_mask_allowed outside your procedure and that's all it does then you can do this pIVR := 1. which'll have the same result as your code ( procedure and function ). Personally if this is somewhere near all they do I'd have everything in the same procedure.
If you're missing some information in is_mask_missing, that then with nothing after it maybe then your package will error on no_data_found as there is the possibility of select 1 from dual where 1 = 0, which returns nothing.
If you do want is_mask_allowed to be accessed outside your procedure it would be easiest to put it in a package. As you can't use a boolean I've used a binary, where 0 represents false and 1 true
create or replace package my_package is
function is_mask_allowed ( pBusSeg IN NUMBER
, pCHTPMask IN NUMBER
) RETURN NUMBER;
procedure get_info ( pIVR out NUMBER );
end my_package;
/
show error
create or replace package body my_package is
function is_mask_allowed ( pBusSeg IN NUMBER
, pCHTPMask IN NUMBER
) RETURN NUMBER is
begin
if pCHTPMask > 0 THEN
-- do something
return 0
else return 1
end if;
end is_mask_allowed;
-----------------------------------
procedure getinfo( pIVR OUT NUMBER ) IS
begin
if is_mask_allowed(1,2) = 1 then
pIVR := 1;
else
pIVR := -- something else;
end if;
end getinfo;
end my_package;
/
show error
You need to put your is_mask_allowed function into a package to use it in SQL, and you should return something other than a boolean (perhaps a number) from the function and test for that, so your SQL is something more like:
select my_pkg.is_mask_allowed(1, 2) into pIVR from dual;
Here is a recent discussion in the Oracle forums on the same error:
https://forums.oracle.com/forums/thread.jspa?threadID=2319500

Resources