misunderstanding in formating a phone number using oracle pl/sql - oracle

CREATE OR REPLACE PROCEDURE format_phone_number
(p_phone_number IN OUT VARCHAR2)
IS
BEGIN
p_phone_number := '(' || SUBSTR(p_phone_number,1,3) || ')' ||
'-' || SUBSTR(p_phone_number,4,3) ||
'.' || SUBSTR(p_phone_number,7,4);
END format_phone_number;
-------------------------------------------------
DECLARE
v_number VARCHAR2(25) := '8002019201';
BEGIN
format_phone_number(v_number);
DBMS_OUTPUT.PUT_LINE(v_number);
END;
Output is ok (800)-201.9201. Question is why after i cut from the procedure like this for example :
CREATE OR REPLACE PROCEDURE format_phone_number
(p_phone_number IN OUT VARCHAR2)
IS
BEGIN
p_phone_number := '(' || SUBSTR(p_phone_number,1,3) || ')';
END format_phone_number;
After invoking again, it gives me only this (800) and not (800)2019201 "unformated" like. Is this a kind of a regular expression and it just can't parse the whole thing because of the limitation of initalization in the p_phone_number from the procedure?

The code is doing exactly what you told it to do. In the second code block only three characters are being taken from the initial value of p_phone_number. These three characters, and the leading and trailing parentheses, then replace the original contents of p_phone_number when the assignment is made. To get the result you're expecting you'd need to use:
p_phone_number := '(' || SUBSTR(p_phone_number,1,3) || ')' ||
SUBSTR(p_phone_number, 4, 7);
Share and enjoy.

Related

Oracle pl/sql Array

let's see if somebody can help me, I need to delete rows from different tables and I did think to do it using an array so i wrote this :
DECLARE
TYPE mytype_a IS TABLE OF VARCHAR2(32) INDEX BY BINARY_INTEGER;
mytype mytype_a;
BEGIN
mytype(mytype.count + 1) := 'MYTABLE';
FOR i IN 1 .. mytype.count
LOOP
DELETE mytype(i) WHERE valid = 'N';
END LOOP;
END;
Trying to run this piece of code using sqldeveloper I get the ORA-00933 command not properly ended, if I put directly the table name it works, what am I doing wrong?
Thank you.
Thank you very much guys, it works perfectly.
This is not the correct approach. You have to use Dynamic SQL for this -
DECLARE
type mytype_a is table of varchar2(32) index by binary_integer;
mytype mytype_a;
stmt varchar(500) := NULL;
BEGIN
mytype (mytype.count + 1) := 'MYTABLE';
for i in 1..mytype.count loop
stmt := 'DELETE FROM ' || mytype(i) || ' where valid =''N''';
EXECUTE IMMEDIATE stmt;
end loop;
END;
You would need to use dynamic SQL, concatenating the table name from the collection into the statement, inside your loop:
execute immediate 'DELETE FROM ' || mytype(i) || ' where valid = ''N''';
Or you can put the statement into a variable so you can display it for debugging purposes, and then execute that, optionally with a bind variable for the valid value:
stmt := 'DELETE FROM ' || mytype(i) || ' where valid = :valid';
dbms_output.put_line(stmt);
execute immediate stmt using 'N';
dbms_output.put_line('Deleted ' || sql%rowcount || ' row(s)');
... which I've made also display how many rows were deleted from each table. Note though that you shoudln't rely on the caller being able to see anything printed with dbms_output - it's up to the client whether it shows it.
The whole anonymous block would then be:
DECLARE
type mytype_a is table of varchar2(32) index by binary_integer;
mytype mytype_a;
stmt varchar2(4000);
BEGIN
mytype (mytype.count + 1) := 'MYTABLE';
for i in 1..mytype.count loop
stmt := 'DELETE FROM ' || mytype(i) || ' where valid = :valid';
dbms_output.put_line(stmt);
execute immediate stmt using 'N';
dbms_output.put_line('Deleted ' || sql%rowcount || ' row(s)');
end loop;
END;
/
You could use a built-in collection type to simplify it even further.
db<>fiddle showing some options.
Hopefully this doesn't apply, but if you might have any tables with quoted identifiers then you would need to add quotes in the dynamic statement, e.g.:
stmt := 'DELETE FROM "' || mytype(i) || '" where valid = :valid';
... and make sure the table name values in your collection exactly match the names as they appear in the data dictionary (user_tables.table_name).

PLS-00306: wrong number or types of arguments in call to 'fun'

I'm trying to call an function with table type argument which is defined in package scope, but got error:
PLS-00306: wrong number or types of arguments in call to 'fun'.
CREATE OR REPLACE PACKAGE pkg AS
TYPE aging_sch_record_type IS
RECORD (days_delq NUMBER, eligible NUMBER, unit NUMBER, balance NUMBER);
TYPE aging_sch_table_type IS
TABLE OF aging_sch_record_type INDEX BY VARCHAR2(20);
PROCEDURE proc ();
FUNCTION fun (v_aging_sch_table aging_sch_table_type,
v_days_delq NUMBER, v_eligible NUMBER) RETURN NUMBER;
END pkg;
create or replace PACKAGE BODY pkg AS
PROCEDURE proc () AS
CURSOR aging_sch_cursor IS
SELECT ...
GROUP BY ...;
v_aging_sch_row aging_sch_cursor%rowtype;
v_aging_sch_table aging_sch_table_type;
BEGIN
FOR v_aging_sch_row IN aging_sch_cursor LOOP
v_aging_sch_table(v_aging_sch_row.days_delq || ' ' || v_aging_sch_row.eligible).days_delq := v_aging_sch_row.days_delq;
v_aging_sch_table(v_aging_sch_row.days_delq || ' ' || v_aging_sch_row.eligible).eligible := v_aging_sch_row.eligible;
v_aging_sch_table(v_aging_sch_row.days_delq || ' ' || v_aging_sch_row.eligible).unit := v_aging_sch_row.unit;
v_aging_sch_table(v_aging_sch_row.days_delq || ' ' || v_aging_sch_row.eligible).balance := v_aging_sch_row.balance;
END LOOP;
INSERT INTO t
VALUES (fun(v_aging_sch_table,0,2));
END proc;
FUNCTION fun (v_aging_sch_table aging_sch_table_type,
v_days_delq NUMBER, v_eligible NUMBER) RETURN NUMBER
AS
BEGIN
...
END fun;
END pkg;
Any idea on what the problem?
Thanks.
You cannot use associative array in SQL (and you cannot use any array declared in package specification in SQL in Oracle versions prior to 12c), but you can store result of the fun function into local variable, and then insert that variable into table t:
PROCEDURE proc () AS
CURSOR aging_sch_cursor IS
SELECT ...
GROUP BY ...;
v_aging_sch_row aging_sch_cursor%rowtype;
v_aging_sch_table aging_sch_table_type;
v_fun number;
BEGIN
FOR v_aging_sch_row IN aging_sch_cursor LOOP
v_aging_sch_table(v_aging_sch_row.days_delq || ' ' || v_aging_sch_row.eligible).days_delq := v_aging_sch_row.days_delq;
v_aging_sch_table(v_aging_sch_row.days_delq || ' ' || v_aging_sch_row.eligible).eligible := v_aging_sch_row.eligible;
v_aging_sch_table(v_aging_sch_row.days_delq || ' ' || v_aging_sch_row.eligible).unit := v_aging_sch_row.unit;
v_aging_sch_table(v_aging_sch_row.days_delq || ' ' || v_aging_sch_row.eligible).balance := v_aging_sch_row.balance;
END LOOP;
v_fun := fun(v_aging_sch_table,0,2)
INSERT INTO t
VALUES (v_fun);
END proc;
Furthermore, you are inserting result of the function into table t without naming column - does that table really have only one column? If not, you should name every column into which you are inserting data, as in:
INSERT INTO t (COLUMN1)
VALUES (v_fun);
If you weren't indexing by string you could have used standalone object type and nested table which would have worked in SQL, but in your case that is not an option.

oracle open cursor with string variable gives me errors

I have problems with opening cursor with string variable
here is my oracle database code
FUNCTION f_get_cursor(p_date_to_forecast VARCHAR) RETURN SYS_REFCURSOR AS
v_cursor SYS_REFCURSOR;
v_groupby_stmt VARCHAR(200) := 'GROUP BY '
|| CASE WHEN p_date_to_forecast = 'HOLIDAY' THEN
'DAY, ' ELSE '' END
|| 'TNI, FRMP, LR, HH;';
v_select_stmt VARCHAR2(1000) := 'SELECT WEEKDAY, TNI, FRMP, LR, HH,
AVG(Coalesce(VOLUME, 0)) AS AverageVolume
FROM (SELECT v.TNI, v.FRMP, v.LR, v.DAY,
v.HH, v.VOLUME, CASE WHEN
hd.HOLIDAY_DATE is not null
then ''HOLIDAY''
ELSE trim(to_char(v.DAY, ''Day''))
END AS WEEKDAY
FROM v_nem_rm16 v
LEFT JOIN DBP_ADMIN.DBP_HOLIDAY hd
ON v.DAY = hd.HOLIDAY_DATE
WHERE v.STATEMENT_TYPE !=''FORCAST'')
WHERE WEEKDAY = ''' || p_date_to_forecast
|| '''' || ' ' || v_groupby_stmt;
BEGIN
OPEN v_cursor FOR v_select_stmt;
return v_cursor;
END;
I am just trying to open cursor based on the parameter "p_date_to_forcast", which is just string of the name of the week like "Saturday, Tuesday..and so on" and return the cursor.
When I run the query, I got this error
00911. 00000 - "invalid character"
*Cause: identifiers may not start with any ASCII character other than
letters and numbers. $#_ are also allowed after the first
character. Identifiers enclosed by doublequotes may contain
any character other than a doublequote. Alternative quotes
(q'#...#') cannot use spaces, tabs, or carriage returns as
delimiters. For all other contexts, consult the SQL Language
Reference Manual.
*Action:
What is the problem and How can I fix it???
thanks
Have you tried this
for r_cur in your_cursor_name(Your_parameter) Loop
-- your working --
End loop;

ORA-06550: line 3, column 2: PLS-00103: Encountered the symbol "1" when expecting one of the following:

I get this error message:
ORA-06550: line 3, column 2: PLS-00103: Encountered the symbol "1"
when expecting one of the following:
begin function pragma procedure subtype type current cursor delete exists prior
For this code in oracle apex web application:
declare
1_address varchar2(4000);
1_url varchar2(32000);
1_response varchar2(3200);
begin
1_address := :P3_STREET || ',' || :P3_CITY;
if :P3_STATE is not null then
1_address := 1_address || ',' || :P3_STATE;
end if;
if :P3_COUNTRY is not null then
1_address := 1_address || ',' || :P3_COUNTRY;
end if;
1_address := replace(1_address, ' ', '+');
1_url := 'http://maps.google.com/maps/geo?q=' || 1_address || '&' ||
'output=c sv' || '&' || 'key=' || :API_KEY;
1_response := utl_http.request(1_url, APEX_APPLICATION.G_PROXY_SERVER);
:P3_RESPONSE := 1_response;
:P3_LOCATION := substr(1_response, instr(1_response, ',', 1, 2) + 1);
end;
I would like to integrate google maps to my application.
I followed this instruction, but it doesn't work.
Anybody have idea for solution?
Oracle naming conventions require (see here):
Nonquoted identifiers must begin with an alphabetic character from your database character set. Quoted identifiers can begin with any character.
The same also applies to PL/SQL variable names (see here):
Variable names can be composed of letters, dollar signs, underscores,
and number signs.
No other characters can be used.
A variable name must start with a letter, after which any combination
of the allowed characters can be used.
The maximum length for a variable name is 30 characters.
Variable names, like those of keywords and other identifiers, are not
case sensitive.
So, change the name of your variables to something that is acceptable to Oracle. In other words, don't start them with 1.

PLSQL: generate next unique key of a specific size

I have a table in which there is a primary key named CODE of Type VARCHAR(3). The problem is that all the available values from 000,001 .... 999 are used in different records. As the field CODE is in varchar format so we can have alphabets along with digits.
Is there any algorithm or function in plsql through which we can uniformly generate unique keys of length 3 which includes alphabets as well. Note that we cannot change the field size as it is referenced in so many other tables.
what about this solution
generate alpha-numeric code based on oracle sequence
please check code
declare
l_val number := 255; -- SQN_TMP_01.nextval;
l_base number := 62; -- 00azAZ
l_base_str varchar2(62) := '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
l_res number;
l_final varchar2(100);
begin
loop
-- init numberic value
l_val := SQN_TMP_01.nextval;
l_final := null;
dbms_output.put_line(l_val);
-- convert value to alphanumeric code
loop
l_res := mod(l_val, l_base);
l_final := substr(l_base_str, l_res + 1, 1) || l_final;
exit when l_val - l_res = 0;
l_val := trunc((l_val - l_res) / l_base);
dbms_output.put_line('res = ' || l_res || ' l_val = ' || l_val || ' final: "' || l_final || '"');
end loop;
dbms_output.put_line('check final: "' || l_final || '"');
-- exclude full numeric result as already used
exit when trim(translate(l_final, '0123456789', ' ')) is not null;
end loop;
dbms_output.put_line('final string: "' || l_final || '"');
end;
You should almost certainly migrate your field to an integer type. If that's impossible then it should be possible to convert to a larger char field as bpgergo suggests.
If you're really, really stuck with a 3 character limit you could use to_char(id, 'xxx') to convert to hex, as in: Oracle: How do I convert hex to decimal in Oracle SQL?
This would give you up to 4096 entries. It should be possible (but more complex) to use base64 (up to 262,144 entries), or go up to base 128 (2,097,152), or just use the whole field as a 3 byte unsigned integer if you don't care about the raw data being printable characters (16,777,216).

Resources