I get too many results when compile - oracle

Hey guys i have this function
CREATE OR REPLACE FUNCTION FN_FONO (P_COD IN NUMBER) RETURN NUMBER
IS
V_FONO NUMBER(10);
BEGIN
SELECT
'9'||SUBSTR(CELULAR,4,1)||SUBSTR(CELULAR,7,3)||SUBSTR(CELULAR,-4,14)
INTO V_FONO
FROM PERSONA
JOIN CLIENTE USING(RUT)
WHERE COD_CLIENTE = P_COD;
RETURN V_FONO;
END;
and when i am going to test this i get too many results and i only want one
select fn_fono(1) FROM PERSONA;

You selected "from persona", so your query is returning a result for every row in the persona table. Because you put p_cod=>1 you get the same result back for every row.
Since your query is fully defined inside your function there is no need to reference any of the tables outside the function call. It is typical to use the pseudo-table "dual" when making a function call outside of a PL/SQL block:
select fn_fono(1) from dual;
If referencing the function inside another procedure or PL/SQL block, you would do something like this:
l_fono := fn_fono(1);

In the example the function gets called for each of the rows present in the table PERSONA. if you need it to be run exactly once you would do as follows
select fn_fono(1) FROM PERSONA where rownum=1;

Related

getting error of character string buffer too small even after changing to varchar(32000)

getting error QRA-06502 of character string buffer too small even after changing to varchar(32000)
create or replace function product_purchase(CUSTOMER_COD VARCHAR2) return varchar is
CODE VARCHAR2(32000);
BEGIN
CODE := ' ';
FOR PRODUCTS_INFO IN (SELECT CUSTOMER_CODE,PRODUCT_NAME
FROM ORDER_DETAIL JOIN ORDERS
ON ORDER_DETAIL.ORDER_ID = ORDERS.ORDER_ID)
LOOP
CODE := CODE || PRODUCTS_INFO.CUSTOMER_CODE||PRODUCTS_INFO.PRODUCT_NAME ||',';
END LOOP;
RETURN CODE;
END product_purchase;
/
ERROR MAINLY OCCURS WHILE SELECTING DATA AND PUTTING IT IN THE FUNCTION
SELECT CUSTOMER_CODE ,product_purchase(CUSTOMER_CODE),COUNT(PRODUCT_NAME)
FROM ORDER_DETAIL JOIN ORDERS
ON ORDER_DETAIL.ORDER_ID = ORDERS.ORDER_ID
GROUP BY CUSTOMER_CODE,product_purchase(CUSTOMER_CODE)
HAVING COUNT(PRODUCT_NAME)=3;
Even after changing to varchar2(32000)? Well, that doesn't guarantee that you'll get the result (obviously).
The way I see it, it is cursor query that is wrong. If you're calling a function as
product_purchase(CUSTOMER_CODE)
it means that you're passing a parameter to it (you didn't post the whole function code so I'll presume that parameter's name is par_customer_code; note that it shouldn't be just customer_code as it is equal to column name and you'll get unexpected result once you use the parameter).
Exactly - use the parameter. Code you wrote doesn't use it. Should've been
SELECT CUSTOMER_CODE,PRODUCT_NAME
FROM ORDER_DETAIL JOIN ORDERS
ON ORDER_DETAIL.ORDER_ID = ORDERS.ORDER_ID
WHERE customer_code = par_customer_code --> this
I guess that - applying that change - you won't have problems.
However, if you do, then check whether code you wrote actually works, run the cursor query itself and see how many rows it returns. Then, restrict number of rows. How? A simple way is to use rownum:
SELECT CUSTOMER_CODE,PRODUCT_NAME
FROM ORDER_DETAIL JOIN ORDERS
ON ORDER_DETAIL.ORDER_ID = ORDERS.ORDER_ID
WHERE customer_code = par_customer_code
AND rownum <= 10; --> this
and run your code again.
If it works, and if it turns out that varchar2 isn't capable of storing that much data, use CLOB datatype instead:
DECLARE
CODE CLOB; --> this

Parameter for IN query oracle [duplicate]

This question already has an answer here:
Oracle: Dynamic query with IN clause using cursor
(1 answer)
Closed 8 years ago.
SELECT * FROM EMPLOYEE
WHERE EMP_NAME IN (:EMP_NAME);
This is my query and now the EMP_NAME parameter I would like to send it as a list of strings.
When I run this query in SQL developer it is asked to send the EMP_NAME as a parameter, Now I want to send 'Kiran','Joshi' (Basically, I want to fetch the details of the employee with employee name either Kiran or Joshi. How should I pass the value during the execution of the query?
It works when I use the value Kiran alone, but when I concatenate with any other string it won't work. Any pointers in this?
I tried the one below
'Kiran','Joshi'
The above way doesn't work as understood this is a single parameter it tries the employee with the name as 'Kiran',Joshi' which won't come. Understandable, but in order to achieve this thing, how can I go ahead?
Any help would be really appreciated.
Thanks to the people who helped me in solving this problem.
I could get the solution using the way proposed, below is the approach
SELECT * FROM EMPLOYEE WHERE EMP_NAME IN (&EMP_NAME)
I have tried in this way and following are the scenarios which I have tested and they are working fine.
Scenario 1:
To fetch details of only "Kiran", then in this case the value of EMP_NAME when sql developer prompts is given as Kiran. It worked.
Scenario 2:
To fetch details of either "Kiran" or "Joshi", then the value of EMP_NAME is sent as
Kiran','Joshi
It worked in this case also.
Thanks Kedarnath for helping me in achieving the solution :)
IN clause would be implicitly converted into multiple OR conditions.. and the limit is 1000.. Also query with bind variable means, the execution plan will be reused.. Supporting bind variables for IN clause will hence affect the bind variable's basic usage, and hence oracle limits it at syntax level itself.
Only way is like name in (:1,:2) and bind the other values..
for this, you might dynamic SQL constructing the in clause bind variables in a loop.
Other way is, calling a procedure or function(pl/sql)
DECLARE
v_mystring VARCHAR(50);
v_my_ref_cursor sys_refcursor;
in_string varchar2='''Kiran'',''Joshi''';
id2 varchar2(10):='123'; --- if some other value you have to compare
myrecord tablename%rowtype;
BEGIN
v_mystring := 'SELECT a.*... from tablename a where name= :id2 and
id in('||in_string||')';
OPEN v_my_ref_cursor FOR v_mystring USING id2;
LOOP
FETCH v_my_ref_cursor INTO myrecord;
EXIT WHEN v_my_ref_cursor%NOTFOUND;
..
-- your processing
END LOOP;
CLOSE v_my_ref_cursor;
END;
IN clause supports maximum of 1000 items. You can always use a table to join instead. That table might be a Global Temporary Table(GTT) whose data is visible to thats particular session.
Still you can use a nested table also for it(like PL/SQL table)
TABLE() will convert a PL/Sql table as a SQL understandable table object(an object actually)
A simple example of it below.
CREATE TYPE pr AS OBJECT
(pr NUMBER);
/
CREATE TYPE prList AS TABLE OF pr;
/
declare
myPrList prList := prList ();
cursor lc is
select *
from (select a.*
from yourtable a
TABLE(CAST(myPrList as prList)) my_list
where
a.pr = my_list.pr
order by a.pr desc) ;
rec lc%ROWTYPE;
BEGIN
/*Populate the Nested Table, with whatever collection you have */
myPrList := prList ( pr(91),
pr(80));
/*
Sample code: for populating from your TABLE OF NUMBER type
FOR I IN 1..your_input_array.COUNT
LOOP
myPrList.EXTEND;
myPrList(I) := pr(your_input_array(I));
END LOOP;
*/
open lc;
loop
FETCH lc into rec;
exit when lc%NOTFOUND; -- Your Exit WHEN condition should be checked afte FETCH iyself!
dbms_output.put_line(rec.pr);
end loop;
close lc;
END;
/

Oracle Get two variables returned from select query inside of a package

I modified the procedure to make it smaller but I really only want to run the select query once. This will reduce the cost of running the procedure. How can I get the prevContectID and nextContentID without running the query twice. This is replacing a previous procedure so I do not want to change the IN and OUT so I do not have to find every where it is being called.
procedure getSeq(theContentID IN table.contentID%type,
prevContentID OUT table.contentID%type,
nextContentID OUT table.contentID%type)
BEGIN
SELECT myPrev into prevContentID, myNext into nextContentID
from myTable
where contentID=theContentID;
RETURN;
END getSeq;
The shown procedure most likely doesn't compile. The correct syntax for SELECT ... INTO using several variables is:
SELECT myPrev, myNext INTO prevContentID, nextContentID
from myTable
where contentID = theContentID;
You can also use a cursor to fetch the values from myTable.For your approach you need to do proper exception handling ,when theContentID does not exists in myTable,because that will give you NO_DATA_FOUND exception.
PROCEDURE getSeq (theContentID IN table.contentID%TYPE,
prevContentID OUT table.contentID%TYPE,
nextContentID OUT table.contentID%TYPE)
IS
CURSOR getcontentID_cur
IS
SELECT myPrev, myNext
FROM myTable
WHERE contentID = theContentID;
BEGIN
OPEN getcontentID_cur;
FETCH getcontentID_cur
INTO prevContentID, nextContentID;
CLOSE getcontentID_cur;
END getSeq;

Functional Where-In Clause - Oracle PL/SQL

I've got an association table that groups accounts together.
I'm trying to select a subset of table 'target'
p_group_id := 7;
select *
target t
where t.account_id in get_account_ids(p_group_id);
Is it possible to write a function that returns a list of account_ids (as some form of collection) that would facilitate the above code?
I've looked at pipelined functions, however I want to stay away from loops and cursors. Also, custom types / table also get into casting that I'd like to avoid.
For reference, here's some pseudocode for what the function 'get_account_ids' would do, hypothetically:
function get_account_ids(p_group_id)
insert into v_ret
select aa.account_id
from assoc_account aa
where aa.groupid = p_group_id;
return v_ret;
You simply need:
select *
from target t
where t.account_id in
( select aa.account_id
from assoc_account aa
where aa.groupid = 7;
)
The above will work, assuming that assoc_account.account_id is never NULL.

Oracle function to return a table included in a where clause

I would like to create a function which returns a table of results. Something like
select * from address where zipcode in (f_zips_in_radius(45.123,-93.123,50));
I have been working on that function but don't have anything working so will exclude my attempts so as not to muddle the question.
Assuming that it is possible, How would I implement it?
A combination of comments lead me to that answer. Thanks #a_horse_with_no_name and #Ray Toal
Here was my final solution
CREATE OR REPLACE PACKAGE pkg_distance AS
TYPE vcharset_t IS TABLE OF VARCHAR2(20);
FUNCTION zips_in_radius(i_lat number, i_lon number, i_radius NUMBER) RETURN vcharset_t PIPELINED;
END;
/
CREATE OR REPLACE PACKAGE BODY pkg_distance AS
FUNCTION zips_in_radius(i_lat number, i_lon number, i_radius NUMBER) RETURN vcharset_t PIPELINED IS
BEGIN
for r in (
select zipcode from zipdata z where f_distance(i_lat, i_lon, z.lat, z.lon) <= i_radius
)
loop
pipe row ( r.zipcode);
end loop;
return;
END;
END;
Then to use it I am using a query like:
--Boston City Centered on 42.360637,-71.0587120
select * from address a
where substr(a.zipcode,1,5) in
(select * from TABLE(pkg_distance.zips_in_radius(42.360637,-71.0587120,60)))
Which in my opinion still has an extra "select * from TABLE(" for my comfort, but still managable.
The problem is zipcode can be anything so if u r treating like a number then it becomes easier. You have to compute every possible permutation between x and y and then pass it back.
Since I donot know your app and your case, how many results can you expect ? Because that in clause can be very costly and you might have to do materialize the result set.. Or do some clever tricks....
Also I am guessing you have to cast this into a table...

Resources