Storing multiple parameters into one variable Oracle 11G - oracle

I am working on an assignment. What I want to do is store two parameter values into one variable value. My code at the moment is this:
create or replace function generateISIN(
countryCode Country.Code%type,
universityCode University.Code%type,
studentNumber varchar2)
return varchar2
as
v_numbers varchar2(9);
newStudentNumber varchar2(50) := '';
begin
select co.code, un.code
into newStudentNumber
from country co, university un
where v_numbers = studentNumber;
dbms_output.put_line('implementeer deze functie verder...');
return newStudentNumber;
end;
/
The meaning of this program/code is to get the country code (US, NL, AUS, etc..) and the university code (RUS, TUE, TIU, etc..) into one variable. So in the end I will get a ISIN
International Student Identification Number
For example: NL 1234 5678 944 TUE
Any idea how to combine the country code and university code with a number?

Assuming your variable is big enough to hold the result, you can simply concatenate the columns using the string concatenation operator ||:
select co.code || un.code
into newStudentNumber
from country co, university un
where v_numbers = studentNumber;

You could simply concatenate the column values using the concatenate operator || or the CONCAT function.
For example,
select co.code ||' '|| un.code
into newStudentNumber
from country co, university un
where v_numbers = studentNumber;
I have used a space in between just to make sure that the output is clear and each code is separated by a space.
Update You need to correct your query:
select co.code, un.code
into newStudentNumber
from country co, university un
where v_numbers = studentNumber;
You have a Cartesian join since the filter predicate has no real column(s)
On both sides of the operator you have used the local variable, makes no sense. Usually, you would do a comparison in a IF-ELSE construct based on the business logic.
dbms_output.put_line('implementeer deze functie verder...');
DBMS_OUTPUT is a good help while testing your code, however, make sure you don't carry it on production environment.
Also, remember, if you could do something in SQL, then you should not use PL/SQL unless there is a business need. Your entire code could be replaced with a single SQL statement.

Related

comparar fechas de diferentes tablas al detalle de los segundos

Good evening,
I have a SP and I want to compare 2 dates from different tables, but in the form 'dd/mm/yyyy hh:mi:ss'
I am using to_char(date01,'dd/mm/yyyy hh:mi:ss')> to_char(date02,'dd/mm/yyyy hh:mi:ss')
but it throws me errors.
For example: if the date is 02/12/2016 07:40:12>02/02/2022 06:40:46
it indicates that it is true, and it is not, it is considering the day and not the entire date.
when I only use date01>date02, I have the problem you consider for example.
'02/15/2022 07:48:50'='02/15/2022 07:50:22' (only considers the date)
How can I compare date, minutes and seconds regardless of the server configuration.
Thank you,
PROCEDURE SPU_CUENTA
(
p_nro in varchar2,
pr_Ret OUT number
) is
vfecha varchar(100);
vcount int;
begin
select COUNT(DFEC_SISTEMA) into vcount from TAB Where c=1;
IF vcount>0 THEN
select to_char(DFEC_SISTEMA,'dd/mm/yyyy hh:mi:ss') into vfecha from TAB Where c=1;
EXECUTE IMMEDIATE 'SELECT COUNT(DFEC_ANULA) FROM tablab WHERE to_char(DFEC_ANULA,'dd/mm/yyyy hh:mi:ss')>'''||vfecha||'''' into pr_Ret;
END IF;
end;
Code you suggest would make sense if columns involved were VARCHAR2 (which is a bad idea; store dates into DATE datatype columns).
If those columns really are DATEs, then part of your question (which suggests format) is meaningless - we compare dates as they are, simply by e.g. date1 > date2. Converting them to characters - in a format you specified - is plain wrong.
If those columns are strings, then you'll have to convert them TO_DATE, not TO_CHAR
Procedure you wrote should be a function; they are designed to return a value. Yes, you can use a procedure, but - why would you? You can't use it in SQL (only in PL/SQL).
Besides, code can be heavily shortened/optimized, as you need just one select statement. You don't have to first check whether there any rows in tab that satisfy the condition, and then select some other info - use a subquery instead.
Finally, why are you using dynamic SQL? There's nothing dynamic in your code.
I'd suggest something like this, see if it makes sense.
FUNCTION spu_cuenta (p_nro IN VARCHAR2)
RETURN NUMBER
IS
pr_ret NUMBER;
BEGIN
SELECT COUNT (dfec_anula)
INTO pr_ret
FROM tablab
WHERE dfec_anula > (SELECT dfec_sistema
FROM tab
WHERE c = 1);
RETURN pr_ret;
END;

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

Date comparison error when storing with into

Im almost done with a procedure i started yesterday, but on the last step i have found a problem that happens only if a comparison is done with an if clause. The procedure shows all the information of a match if you introduce a football league round and the name of a team. Im storing the football match id on idp for later comparisons when the team is either the home or the away team and the date matches with one of the two rounds available (the if clause sets a different date to a variable called FECHA if it is either one or two). The thing is that, if i try to check the FECHA or date in spanish manually, it works, but if i try using the if path, an error appears claiming:
Could you help me solve that? Thank you so much!
create or replace PROCEDURE COMPROBARPARTIDO(JORNADA IN NUMBER, EQUIPO IN VARCHAR2) AS
FECHA DATE;
IDLOCAL NUMBER;
IDP NUMBER;
NUMAUX NUMBER;
NUMAUX2 NUMBER;
GOLAUX NUMBER;
GOLOC NUMBER;
GOLVI NUMBER;
BEGIN
NUMAUX:=0;
NUMAUX2:=0;
IF JORNADA = 1 THEN
FECHA := TO_DATE('2021-03-04','yyyy-mm-dd');
ELSIF JORNADA = 2 THEN
FECHA := TO_DATE('2021-03-13','yyyy-mm-dd');
ELSE
DBMS_OUTPUT.PUT_LINE('ERROR');
END IF;
SELECT DISTINCT P.ID INTO IDP
FROM PARTIDO P
INNER JOIN EQUIPO EL
ON P.ID_LOCAL =EL.ID
INNER JOIN EQUIPO EV
ON P.ID_VISITANTE = EV.ID
WHERE P.FECHA = FECHA AND (EV.NOMBRE =EQUIPO OR EL.NOMBRE=EQUIPO);
You are doing:
WHERE P.FECHA = FECHA
From the documentation:
If a SQL statement references a name that belongs to both a column and either a local variable or formal parameter, then the column name takes precedence.
So that means that condition is equivalent to:
WHERE P.FECHA = P.FECHA
which is always true (unless P.FECHA is null). That means you are finding all rows where (EV.NOMBRE =EQUIPO OR EL.NOMBRE=EQUIPO), regardless of the P.FECHA value. That is giving you more rows than you expect; as you are using select ... into ... the query has to return exactly one row, and presumably does when you hard-code a date.
You should either explicitly prefix your variable name with the procedure name to give it context:
WHERE P.FECHA = COMPROBARPARTIDO.FECHA
or rename you local variable; it's fairly common to add a L_ prefix to local variable names and P_ for parameter names, for example, to distinguish them from column names:
create or replace PROCEDURE COMPROBARPARTIDO(P_JORNADA IN NUMBER, P_EQUIPO IN VARCHAR2) AS
L_FECHA DATE;
...
and change all the references to match:
WHERE P.FECHA = L_FECHA

PL/SQL Stored proc that uses a comma separated parameter to drive a dynamic LIKE clause?

Is there a fairly simple way to take an input parameter containing a comma seperated list of prefixes and return a cursor based on a select statement that uses these?
i.e. (Pseudocode)
PROCEDURE get_by_prefix(p_list_of_prefixes IN varchar2, r_csr OUT SYS_REFCURSOR)
IS
BEGIN
OPEN r_csr FOR
SELECT * FROM my_table where some_column LIKE (the_individual_fields_from p_list_of_prefixes ||'%')
END
I've tried various combinations, and now have two problems - coercing the input into a suitable table (I think it needs to go into a table type rather than a VARCHAR2_TABLE), and secondly getting the like clause to be effectively a SELECT from an internal 'pseudotable'...
EDIT: It seems that people are suggesting ways to use 'IN' with a set of potential values - whereas Im looking at using LIKE. I could use a similar technique - building up dynamic SQL, but was wondering if there isnt a more elegant way...
PL/SQL has no concept of a comma-separated list and no built-in splitter as in Perl etc, so you'll have to use one of the hand-rolled methods such as this one:
https://stewashton.wordpress.com/2016/08/01/splitting-strings-surprise
(Other methods are available.) Then it's just a matter of either populating a collection in one step and using it in the next, or else combining the two as something like this:
declare
p_list_of_prefixes varchar2(100) := 'John,Jim,Jules,Janice,Jenny';
begin
open :refcur for
with params as
( select x.firstname
from xmltable(
'ora:tokenize($X, "\,")'
passing p_list_of_prefixes as x
columns firstname varchar2(4000) path '.'
) x
)
, people as
( select 'Dave Clark' as fullname from dual union all
select 'Jim Potter' from dual union all
select 'Jenny Jones' from dual
)
select x.firstname, p.fullname
from params x
left join people p on p.fullname like x.firstname || '%';
end;
Output:
FIRSTNAME FULLNAME
-------------- -----------
John
Jim Jim Potter
Jules
Janice
Jenny Jenny Jones
Using LIKE the way you want is easy, but it is the wrong solution. (See my Comment under the original post).
Anyway - if by order of your superiors, or some other semi-legitimate reason, you must use a LIKE condition, it should look something like this:
... where ',' || p_list_of_whatever || ',' like '%,' || some_column || ',%
Concatenating commas at both ends of both sides of the comparison is needed, because you don't want Jo in the column to match John in the input list. Start from there and you will see why you need the commas on the right-hand side, and then follow from there and you will see why you need them on the left also.

Oracle create operator

I've recently run into a case where a fuzzy-match was useful when categorizing historical unstructured-string data. UTL_MATCH is great and has worked well when wrapping into a truthy fuzzy-match function. But I wanted to be joining ad-hoc, and took the route of building out a new function-based operator.
OPERATOR creation: (function-based, FUZZY_MATCH returns 0 for unmatched, 1 for match. A dummy version is included here)
CREATE OR REPLACE FUNCTION FUZZY_MATCH(
LEFT_ITEM VARCHAR2,
RIGHT_ITEM VARCHAR2 )
RETURN NUMBER AS BEGIN
RETURN 1;
END;
CREATE OR REPLACE OPERATOR RESEMBLES
BINDING (VARCHAR2, VARCHAR2)
RETURN NUMBER USING FUZZY_MATCH
;
Creating a new operator works fine, but I've been a little dissatisfied with the resultant sql syntax (example below).
CREATE TABLE LEFT_TABLE(ARBITRARY_DATA VARCHAR2(200) NOT NULL);
CREATE TABLE RIGHT_TABLE(ARBITRARY_DATA VARCHAR2(200) NOT NULL);
INSERT INTO LEFT_TABLE VALUES ('In a hole in the ground there lived a hobbit.');
INSERT INTO RIGHT_TABLE VALUES ('In the ground there lived a hobbit.');
SELECT
LEFT_TABLE.ARBITRARY_DATA LEFT_DATA,
RIGHT_TABLE.ARBITRARY_DATA RIGHT_DATA
FROM
LEFT_TABLE
INNER JOIN
RIGHT_TABLE
ON 1 = RESEMBLES ( LEFT_TABLE.ARBITRARY_DATA, RIGHT_TABLE.ARBITRARY_DATA )
;
Is there an alternative OPERATOR definition to make the truthiness of the operator implicit, allowing for more natural syntax like the following? I'm on 11gR2
Thanks
SELECT
LEFT_TABLE.ARBITRARY_DATA LEFT_DATA,
RIGHT_TABLE.ARBITRARY_DATA RIGHT_DATA
FROM
LEFT_TABLE
INNER JOIN
RIGHT_TABLE
ON LEFT_TABLE.ARBITRARY_DATA RESEMBLES RIGHT_TABLE.ARBITRARY_DATA;

Resources