| How to fetch a single record in an array/nested table [message #629941] |
Thu, 18 December 2014 01:15  |
buggleboy007
Messages: 282 Registered: November 2010 Location: Canada
|
Senior Member |
|
|
I would like to know as to how to fetch a single record in an array/nested table. The situation is as follows:
I am using the default EMP table on SCOTT schema
So EMP table is :
DESC EMP
Name Null Type
-------- -------- ------------
EMPNO NOT NULL NUMBER(4)
ENAME VARCHAR2(10)
JOB VARCHAR2(9)
MGR NUMBER(4)
HIREDATE DATE
SAL NUMBER(7,2)
COMM NUMBER(7,2)
DEPTNO NUMBER(2)
Values in EMP table:
select * from emp
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
---------- ---------- --------- ---------- --------- ---------- ---------- ----------
7369 SMITH CLERK 7902 17-DEC-80 800 20
7499 ALLEN SALESMAN 7698 20-FEB-81 1600 300 30
7521 WARD SALESMAN 7698 22-FEB-81 1250 500 30
7566 JONES MANAGER 7839 02-APR-81 2975 20
7654 MARTIN SALESMAN 7698 28-SEP-81 1250 1400 30
7698 BLAKE MANAGER 7839 01-MAY-81 2850 30
7782 CLARK MANAGER 7839 09-JUN-81 2450 10
7788 SCOTT ANALYST 7566 19-APR-87 3000 20
7839 KING PRESIDENT 17-NOV-81 5000 10
7844 TURNER SALESMAN 7698 08-SEP-81 1500 0 30
7876 ADAMS CLERK 7788 23-MAY-87 1100 20
7900 JAMES CLERK 7698 03-DEC-81 950 30
7902 FORD ANALYST 7566 03-DEC-81 3000 20
7934 MILLER CLERK 7782 23-JAN-82 1300 10
14 rows selected
Now I want to access an employee with empno = 7499 into a emp record. My code is as follows:
SET SERVEROUTPUT ON
SET ECHO ON
DECLARE
TYPE emp_type IS TABLE OF emp%ROWTYPE;
emp_dtls emp_type;
BEGIN
emp_dtls:=emp_type();
emp_dtls.EXTEND;
SELECT *
INTO emp_dtls
FROM emp
WHERE empno=7499;
--DBMS_OUTPUT.put_line('Employee details are'||' '||emp_dtls);
END;
/
When I run it, I am getting bogged down with the following error:
Error report -
ORA-06550: line 11, column 8:
PLS-00642: local collection types not allowed in SQL statements
ORA-06550: line 12, column 3:
PL/SQL: ORA-00947: not enough values
ORA-06550: line 10, column 3:
PL/SQL: SQL Statement ignored
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
I did look up a few sites/books before coming here but have not been successful. The only solution that seems to be working is:
SELECT *
INTO emp_dtls(1)
FROM emp
WHERE empno=7499;
This I found in SF's text book, but then I am unable to know the significance of it and hence don't want to use it blindly. Could any one help me out?
Thanks,
Sandeep
|
|
|
|
|
|
| Re: How to fetch a single record in an array/nested table [message #629944 is a reply to message #629943] |
Thu, 18 December 2014 01:35   |
buggleboy007
Messages: 282 Registered: November 2010 Location: Canada
|
Senior Member |
|
|
I agree that it would work the you have shown Michel. My intention is not to use Scalar variable but to use Composite types or rather collections specifically NESTED tables.
The reason I am doing this is because this is one of my weak areas which needs improvement and hence I am trying to gain some good knowledge on it.
I am still looking for answer using Nested tables. Any thoughts?
|
|
|
|
|
|
|
|
| Re: How to fetch a single record in an array/nested table [message #629948 is a reply to message #629946] |
Thu, 18 December 2014 01:45   |
buggleboy007
Messages: 282 Registered: November 2010 Location: Canada
|
Senior Member |
|
|
Is my method:
SET SERVEROUTPUT ON
SET ECHO ON
DECLARE
TYPE emp_type IS TABLE OF emp%ROWTYPE;
emp_dtls emp_type;
BEGIN
emp_dtls:=emp_type();
emp_dtls.EXTEND;
SELECT *
INTO emp_dtls
FROM emp
WHERE empno=7499;
--DBMS_OUTPUT.put_line('Employee details are'||' '||emp_dtls);
END;
/
incorrect or wrong? Can we not achieve the same using SELECT *
INTO emp_dtls(1) -- instead of INTO emp_dtls
FROM emp
WHERE empno=7499;
|
|
|
|
|
|
| Re: How to fetch a single record in an array/nested table [message #629952 is a reply to message #629950] |
Thu, 18 December 2014 01:54   |
buggleboy007
Messages: 282 Registered: November 2010 Location: Canada
|
Senior Member |
|
|
Point noted. In a case where the return type is an array (nested table), and the value that we are retrieving is a VARCHAR then there will be mismatch of values and oracle throws an error. In a situation like this, how can we handle i.e. how do we convert VARCHAR return type to an array(nested table).
|
|
|
|
|
|
|
|
|
|
| Re: How to fetch a single record in an array/nested table [message #629957 is a reply to message #629956] |
Thu, 18 December 2014 02:06   |
buggleboy007
Messages: 282 Registered: November 2010 Location: Canada
|
Senior Member |
|
|
I am not disputing your answer. May be I have not asked it in a proper manner to get the answer that I am looking for. Hence with some real time data/example from work, I will check with you so that you can answer the answer that I am looking for.
BTW- Is there any good resource for COLLECTIONS(VARRAYS,NESTED TABLES OR AA) to gain more mastery on the subject(other than oracle manual)?
|
|
|
|
|
|
|
|
| Re: How to fetch a single record in an array/nested table [message #630011 is a reply to message #629953] |
Thu, 18 December 2014 09:49   |
Solomon Yakobson
Messages: 3310 Registered: January 2010 Location: Connecticut, USA
|
Senior Member |
|
|
Michel Cadot wrote on Thu, 18 December 2014 02:58
If you want to get into a scalar you use simple INTO.
Well, not exactly. You use INTO when query returns one and only one row. Returned value can be scalar or non-scalar. In example below both INTO anb BULK COLLECT INTO will populate non-scalar v_ename_list:
SQL> declare
2 v_ename_list sys.OdciVarchar2List;
3 begin
4 select cast(collect(ename) as sys.OdciVarchar2List)
5 into v_ename_list
6 from emp;
7 select ename
8 bulk collect into v_ename_list
9 from emp;
10 end;
11 /
PL/SQL procedure successfully completed.
SQL>
SY.
|
|
|
|
| Re: How to fetch a single record in an array/nested table [message #630017 is a reply to message #630011] |
Thu, 18 December 2014 10:59   |
 |
Michel Cadot
Messages: 68776 Registered: March 2007 Location: Saint-Maur, France, https...
|
Senior Member Account Moderator |
|
|
You are right, of course, but I'd not recommend such a use unless you have a very specific need of this. It'll be less maintainable as very few know the COLLECT function, and less performant.
SQL> declare
2 v_ename_list sys.OdciVarchar2List;
3 s PLS_INTEGER;
4 begin
5 s := dbms_utility.get_time();
6 for i in 1..100000 loop
7 select cast(collect(ename) as sys.OdciVarchar2List)
8 into v_ename_list
9 from emp;
10 end loop;
11 dbms_output.put_line('COLLECT '||TO_CHAR((dbms_utility.get_time()-s)/100,'990.00')||'s');
12 s := dbms_utility.get_time();
13 for i in 1..100000 loop
14 select ename
15 bulk collect into v_ename_list
16 from emp;
17 end loop;
18 dbms_output.put_line('BULK '||TO_CHAR((dbms_utility.get_time()-s)/100,'990.00')||'s');
19 end;
20 /
COLLECT 10.76s
BULK 6.20s
PL/SQL procedure successfully completed.
[Updated on: Thu, 18 December 2014 11:00] Report message to a moderator
|
|
|
|
| Re: How to fetch a single record in an array/nested table [message #630028 is a reply to message #630017] |
Thu, 18 December 2014 14:23   |
buggleboy007
Messages: 282 Registered: November 2010 Location: Canada
|
Senior Member |
|
|
This is exactly what my problem was(for which I quoted/depicted an example from SF's pl/sql text book for easier understanding):
If you look at the function below, the return type of the function is an array and is defined as:
TYPE typ_array IS TABLE OF VARCHAR2(255);
(This is declared in a different package specification called gzkmail and hence it's referred as gzkmail when it is being called)
Function:
FUNCTION f_getemailids(p_external_code IN GTVSDAX.GTVSDAX_EXTERNAL_CODE%TYPE ,
p_translation_code IN GTVSDAX.GTVSDAX_TRANSLATION_CODE%TYPE,
p_internal_code IN GTVSDAX.GTVSDAX_INTERNAL_CODE_GROUP%TYPE
)
RETURN gzkmail.typ_array IS
--Defining the cursor and using cursor FOR LOOP
CURSOR c_getemailIds IS
SELECT gtvsdax_desc
FROM gtvsdax
WHERE gtvsdax_internal_code_group = p_internal_code
AND gtvsdax_external_code = p_external_code
AND gtvsdax_translation_code = p_translation_code;
v_count NUMBER :=1;
v_return gzkmail.typ_array;
BEGIN
--Initializing the array
v_return:=gzkmail.typ_array();
--Getting the records into the variable v_emailId_rec
<<emailid_loop>>
FOR v_emailId_rec IN c_getemailIds
LOOP
--Increasing number of elements in the array
v_return.EXTEND;
v_return(v_count):=v_emailId_rec.gtvsdax_desc;
v_count:=v_count+1;
END LOOP emailid_loop;
RETURN v_return;
EXCEPTION
WHEN NO_DATA_FOUND THEN
RETURN v_return;
WHEN OTHERS THEN
RETURN v_return;
END f_getemailids;
FUNCTION f_sendmail(p_sender_email IN VARCHAR2,
p_from IN VARCHAR2,
p_to IN gzkmail.typ_array DEFAULT gzkmail.typ_array(),
p_cc IN gzkmail.typ_array DEFAULT gzkmail.typ_array(),
p_bcc IN gzkmail.typ_array DEFAULT gzkmail.typ_array(),
p_msg_subject IN VARCHAR2 DEFAULT NULL,
p_msg_body IN LONG DEFAULT NULL
)
RETURN VARCHAR2 IS
v_to_list LONG;
v_cc_list LONG;
v_bcc_list LONG;
v_date VARCHAR2(255) DEFAULT TO_CHAR(SYSDATE, 'DD MON YYYY HH24:MI:SS PM');
v_errmessage VARCHAR2(2000);
BEGIN
v_errmessage:= 'N';
g_mail_conn := UTL_SMTP.OPEN_CONNECTION(SMTP_HOST, SMTP_PORT);
UTL_SMTP.HELO(g_mail_conn, SMTP_HOST);
UTL_SMTP.MAIL(g_mail_conn, p_sender_email);
v_to_list := f_address_email( 'To: ', p_to );
v_cc_list := f_address_email( 'Cc: ', p_cc );
v_bcc_list := f_address_email( 'Bcc: ', p_bcc );
UTL_SMTP.OPEN_DATA(g_mail_conn );
p_writeData('From: ' || NVL(p_from, p_sender_email));
p_writeData('Subject: ' || NVL(p_msg_subject, '(no subject)'));
p_writeData( v_to_list );
p_writeData( v_cc_list );
UTL_SMTP.WRITE_DATA( g_mail_conn, '' || gzkmail.CRLF );
UTL_SMTP.WRITE_DATA(g_mail_conn, p_msg_body );
UTL_SMTP.CLOSE_DATA(g_mail_conn );
UTL_SMTP.QUIT(g_mail_conn);
RETURN v_errmessage;
EXCEPTION
WHEN utl_smtp.transient_error or utl_smtp.permanent_error THEN
BEGIN
UTL_SMTP.QUIT(g_mail_conn);
EXCEPTION
WHEN utl_smtp.transient_error or utl_smtp.permanent_error THEN
v_errmessage := 'Y';
END;
v_errmessage := 'Y';
RETURN v_errmessage;
WHEN OTHERS THEN
RETURN 'Y';
END f_sendmail;
Now it's time to call the above in an anonymous block for testing:
(The above functions compile successfully and came up with "no errors" when I compiled them at SQL prompt)
SET SERVEROUTPUT ON
SET ECHO ON
DECLARE
v_retval VARCHAR2(200);
BEGIN
v_retval:=gzkmail.f_sendmail(P_sender_email=>f_getemailids('ADVDON','P_SENDER','ADVWEBUSR'),
p_from=>f_getemailids('ADVDON','P_FROM','ADVWEBUSR'),
p_to=>f_getemailids('ADVDON','P_TO','ADVWEBUSR'),
p_msg_subject=>'NEW xxxxxxxxxxx Anonymous User',
p_msg_body=>'A New xxxxxxxx the WEB Today');
END;
Error is:
Error report:
ORA-06550: line 5, column 13:
PLS-00306: wrong number or types of arguments in call to 'F_SENDMAIL'
ORA-06550: line 5, column 13:
PLS-00306: wrong number or types of arguments in call to 'F_SENDMAIL'
ORA-06550: line 5, column 3:
PL/SQL: Statement ignored
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
This is where I am struggling. As the type of the argument is incorrect I am seeing the error above, ANy ideas as to how to hack this one?
[Updated on: Thu, 18 December 2014 14:28] Report message to a moderator
|
|
|
|
|
|
|
|
|
|
| Re: How to fetch a single record in an array/nested table [message #630033 is a reply to message #629999] |
Thu, 18 December 2014 14:35   |
buggleboy007
Messages: 282 Registered: November 2010 Location: Canada
|
Senior Member |
|
|
Quote:I personally prefer books written by Steven Feuerstein but there are a lot of other good authors out there as well.
Correct. I concur with you and no one can beat SF to that matter. However the challenge that I am facing with his book is, when I download the code off the publisher's site and try to open the files to create a schema, I am just unable to find any file that creates a schema and then tables necessary for practicing the examples. I am experiencing SF's book issues on Oracle 12c on Virtual machine box. Then it further says that it's based on HR schema and the required file to run the schema set up is missing completely.
Do you think it would make sense to utilise this book's examples on 11g? I believe in 12c SCOTT schema is also missing.
|
|
|
|
| Re: How to fetch a single record in an array/nested table [message #630034 is a reply to message #630033] |
Thu, 18 December 2014 14:38   |
buggleboy007
Messages: 282 Registered: November 2010 Location: Canada
|
Senior Member |
|
|
Quote:gzkmail.typ_array <> VARCHAR2
There can be only one sender for a mail.
So what do you want to do exactly?
I am trying to send an email out to the respective senders based on the arguments there. The first and second line of argument returns a single value of the type VARCHAR when the return value should be of the type array (gzkmail.typ_aray). So what can be done to fix this?? ie. if the return value is VARCHAR2 which is not an array datatype, how can we convert or hack this?
Quote:
And remove all WHEN OTHERS in your code, they are silly.
I agree with you about WHEN OTHERS. I argued this with my boss but this software shop that I work still wants it. So cannot do much.
[Updated on: Thu, 18 December 2014 14:40] Report message to a moderator
|
|
|
|
|
|
| Re: How to fetch a single record in an array/nested table [message #630036 is a reply to message #630034] |
Thu, 18 December 2014 14:46   |
 |
Michel Cadot
Messages: 68776 Registered: March 2007 Location: Saint-Maur, France, https...
|
Senior Member Account Moderator |
|
|
Quote:I am trying to send an email out to the respective senders based on the arguments there.
If YOU send a mail then YOU are the sender, the other ones are the receivers.
So p_sender_lail and p_from is YOU.
p_to is the others mail.
You just have to convert the array to a list string.
If you use a stored array type instead of a PL/SQL one you could use SQL to do it, for instance:
SQL> select listagg(column_value,',') within group (order by column_value) list
2 from table(sys.odcivarchar2list('michel','cadot','buggleboy007'));
LIST
---------------------------------------------------------------------------------
buggleboy007,cadot,michel
|
|
|
|
|
|
|
|
|
|
| Re: How to fetch a single record in an array/nested table [message #630041 is a reply to message #630039] |
Thu, 18 December 2014 15:05   |
buggleboy007
Messages: 282 Registered: November 2010 Location: Canada
|
Senior Member |
|
|
Code for f_address_email is as follows (basically it's a copy paste of what Tom Kyte on his site has given):
FUNCTION f_address_email( p_string IN VARCHAR2,
p_recipients IN gzkmail.typ_array )
RETURN VARCHAR2
IS
v_recipients LONG DEFAULT NULL;
BEGIN
FOR i IN 1 .. p_recipients.count
LOOP
UTL_SMTP.RCPT(g_mail_conn, p_recipients(i));
IF (v_recipients IS NULL)
THEN
v_recipients := p_string || p_recipients(i);
ELSE
v_recipients := v_recipients || ', ' || p_recipients(i);
END IF;
END LOOP;
RETURN v_recipients;
END f_address_email;
PROCEDURE p_writeData(p_text IN VARCHAR2)
IS
BEGIN
IF (p_text IS NOT NULL)
THEN
UTL_SMTP.WRITE_DATA( g_mail_conn, p_text || gzkmail.CRLF );
END IF;
END;
|
|
|
|
|
|
|
|
| Re: How to fetch a single record in an array/nested table [message #630044 is a reply to message #630042] |
Thu, 18 December 2014 15:15   |
buggleboy007
Messages: 282 Registered: November 2010 Location: Canada
|
Senior Member |
|
|
Well, I have not copied Tom's code as it was there in our shop long time ago. So I cannot go and change it or replace it with UTL_MAIL package as you are aware that UTL_MAIL is not installed by default. DBA has to install it which means I have to sit and convince my boss for the same which I feel will be shot down.
|
|
|
|
|
|
|
|
| Re: How to fetch a single record in an array/nested table [message #630047 is a reply to message #630045] |
Thu, 18 December 2014 15:20   |
buggleboy007
Messages: 282 Registered: November 2010 Location: Canada
|
Senior Member |
|
|
BS: Quote:so many excuses & so little knowledge is a wasteful combination of both your time & our time.
You're on Your Own (YOYO)!
You are wasting your time by participating in this conversation. You only are confronting me with LONG variable and nothing beyond that. Anyways it can be fixed with the following index and this worked fine. I thought by posting my complete question with intellectuals like you, I would be able to expand my "little" knowledge. However you are only hung up on LONG and WHEN OTHERS.
v_retval:=gzkmail.f_sendmail(P_sender_email=>f_getemailids('ADVDON','P_SENDER','ADVWEBUSR')(1),
p_from=>f_getemailids('ADVDON','P_FROM','ADVWEBUSR')(1),
p_to=>f_getemailids('ADVDON','P_TO','ADVWEBUSR'),
p_msg_subject=>'NEW ONLINE xxxxxxxxxxx User',
p_msg_body=>'A New Anonymous xxxxxxxxxx Today');
If you notice I have used (1) after the 1st line, that fixed the thing.
[Updated on: Thu, 18 December 2014 15:21] Report message to a moderator
|
|
|
|
|
|
|
|
|
|
|
|