Why BINARY function doesnt work in SELECT statment - oracle

I am a little bit confusing in using BINARY function in PLSQL and I am not sure if this function even exist in PLSQL since I am new in PLSQL Programming
I want to return 0 or 1 depend if project number is alredy taken or not
SELECT COUNT(*) AS COUNT FROM projects WHERE BINARY CustomName = p_number;
And here is my function
FUNCTION CHECK_PROJECT_NUMBER(p_number NUMBER)
RETURN SYS_REFCURSOR IS
rc SYS_REFCURSOR;
/*CHECK IF PROJECT NUMBER IS TAKEN*/
BEGIN
OPEN rc FOR
SELECT COUNT(*) AS COUNT FROM projects WHERE BINARY CustomName = p_number;
RETURN rc;
END CHECK_PROJECT_NUMBER;
The error which I get is following
Error(869,56): PL/SQL: ORA-00920: invalid relational operator
Where did I made mistake and what I miss here ?

I don't think there is a such function (BINARY) - its a datatype.
There is also a boolean datatype but it is not used in sql (just in plsql).
Also, I do not see any need for cursor for this function, so
I would rewrite it like this:
FUNCTION CHECK_PROJECT_NUMBER(p_number NUMBER)
RETURN NUMBER IS
cnt number:=0;
BEGIN
SELECT COUNT(*) into cnt FROM projects WHERE CustomName =
p_number;
if cnt>0 then
cnt:=1;
end if;
RETURN cnt;
END CHECK_PROJECT_NUMBER;
This function will return 1 if project number is found and 0 otherwise.

Related

Convert SQL Server code to Oracle function

CREATE FUNCTION dbo.Alphaorder (#str VARCHAR(50))
returns VARCHAR(50)
BEGIN
DECLARE #len INT,
#cnt INT =1,
#str1 VARCHAR(50)='',
#output VARCHAR(50)=''
SELECT #len = Len(#str)
WHILE #cnt <= #len
BEGIN
SELECT #str1 += Substring(#str, #cnt, 1) + ','
SET #cnt+=1
END
SELECT #str1 = LEFT(#str1, Len(#str1) - 1)
SELECT #output += Sp_data
FROM (SELECT Split.a.value('.', 'VARCHAR(100)') Sp_data
FROM (SELECT Cast ('<M>' + Replace(#str1, ',', '</M><M>') +
'</M>' AS XML) AS Data) AS A
CROSS APPLY Data.nodes ('/M') AS Split(a)) A
ORDER BY Sp_data
RETURN #output
END
SELECT dbo.Alphaorder ('juan') --> ajnu
That looks like a badly written function to begin with.
If you need to do something like that function does in Oracle SQL, you can do it directly with Oracle SQL features, you don't need to write your own function.
Even if for some reason you do need to write a function, it is perhaps easiest to let SQL do the work for you (the same as you would do if your context was straight SQL).
Something like this:
create or replace function alphaorder(str varchar2) return varchar2
as
output varchar2(4000);
begin
select listagg(ch) within group (order by ch)
into output
from ( select substr(str, level, 1) as ch
from dual
connect by level <= length(str)
)
;
return output;
end;
/
Note that in Oracle you can't limit the length of the input or of the output string; you can only declare the data type. Then in the function itself you can check length and throw an error if the input is longer than 50 characters, but why bother? Let the function work in full generality.
Here's how you would call the function (and check that it works as required):
select alphaorder('juan') as alpha_ordered from dual;
ALPHA_ORDERED
-------------
ajnu

Add inline function with IF/ELSE clause in Oracle 12c

I have table A. If I make a query with inline function
with function f(n number) return varchar2 as
begin
return 'const string';
end;
select id, val, count, f(count) as value from A;
the result will be following:
ID VAL COUNT VALUE
---------- -------------------- ---------- ---------------
1 car 4 const string
2 building 15 const string
But if I try to make the function more complicated
with function f(n number)
return varchar2 as
begin
IF n < 5 THEN
return 'small';
ELSIF n < 50 THEN
return 'normal';
ELSE
return 'big';
END IF;
end;
select id, val, count, f(count) as value from A;
an error message appears:
with function f(n number)
*
ERROR at line 1:
ORA-00905: missing keyword
What's the problem here? Do I use right syntax for the command?
Your if statement is missing a then after the elsif condition clause, hence the missing keyword error pointing to function f. Also, after you fix this error you may get a ORA-00933: SQL command not properly ended pointing to the last semi-colon. Interestingly, the ";" does not seem to work as a terminator to the SQL statement when the PL/SQL declaration is included in the WITH clause. If we attempt to use it on its own, SQL*Plus waits for more text to be entered. So you have to end it with a / on a new line. Even in the example in SQL Reference manual uses a combination of ; and /. Here is my example I tested in PL/SQL Developer 11:
WITH
FUNCTION f(n number) return varchar2 IS
begin
if n<5 then
return 'small';
elsif (n>5 AND n<50) then
return 'medium';
else
return 'big';
end if;
end;
select f(25) from dual
/
Output:
F(25)
medium
EDIT: Also, change your AS to IS in your function definition.

Oracle using the like comparison taken from function in value

I am trying to create a simple function that takes in 3 parameters, 2 numbers and a string. I have written the function but am not getting the expected results from a simple select statement when using the LIKE comparison for the string.
The select from the function below returns no rows when executed with the string input value set to ebts, but if I run this as a standalone select state it returns 2 rows which what I would expect. Have used dbms output to determine if whitespace were being passed but all looks OK.
CREATE OR REPLACE FUNCTION OPC_OP.sitezone_exists
(in_site_id IN NUMBER, in_zone_id IN NUMBER, in_mod VARCHAR2)
RETURN NUMBER
IS
v_count_rec NUMBER;
v_return NUMBER;
v_mod VARCHAR2(4) := in_mod;
BEGIN
SELECT COUNT(*)
INTO v_count_rec
FROM AW_ACTIVE_ALARMS
WHERE AW_ACTIVE_ALARMS.site_id = in_site_id
AND AW_ACTIVE_ALARMS.zone_id = in_zone_id
AND AW_ACTIVE_ALARMS.module LIKE 'v_mod%';
IF v_count_rec > 0
THEN
DBMS_OUTPUT.PUT_LINE('count'||v_count_rec||'=========='||v_mod||'=============');
v_return:= 1;
RETURN (v_return);
ELSE
DBMS_OUTPUT.PUT_LINE('count'||v_count_rec||'=========='||v_mod||'=============');
v_return:= 0;
RETURN (v_return);
END IF;
END sitezone_exists;
When passing in values 12, 12, ebts the output displayed is:
count 0 ==========ebts=============
RetVal = 0
If I run the same select subtituting only passing in the above values the query returns 2 rows - I have removed the like clause of the function and it then returns 2 rows, any idea why the like part of clause is failing to match with rows.
You are trying to match a string literal with this:
AND AW_ACTIVE_ALARMS.module LIKE 'v_mod%';
Change it to:
AND AW_ACTIVE_ALARMS.module LIKE v_mod||'%';
MarioAna has the right answer, IMO, but as an aside (which is too long for a comment), your function can be better written.
You're duplicating the dbms_output code, plus it's considered best practice to have a single RETURN in a function (although I would argue that more might be ok - one in the body and one per exception in the exception block...), so you could rewrite it as:
CREATE OR REPLACE FUNCTION OPC_OP.sitezone_exists
(in_site_id IN NUMBER, in_zone_id IN NUMBER, in_mod VARCHAR2)
RETURN NUMBER
IS
v_count_rec NUMBER;
v_return NUMBER;
v_mod VARCHAR2(4) := in_mod;
BEGIN
SELECT COUNT(*)
INTO v_count_rec
FROM AW_ACTIVE_ALARMS aaa
WHERE aaa.site_id = in_site_id
AND aaa.zone_id = in_zone_id
AND aaa.module LIKE v_mod||'%';
DBMS_OUTPUT.PUT_LINE('count '||v_count_rec||'=========='||v_mod||'=============');
IF v_count_rec > 0 THEN
v_return := 1;
ELSE
v_return:= 0;
END IF;
RETURN (v_return);
END sitezone_exists;
/

Get a array of values form a PLSQL Function

I coded a function to select some flux in a queue and lock them with an updated flag.
I made it with a cursor and it worked great. But i need to get the ID of the flux i locked to process them in my application.
So i start to code a function:
CREATE OR REPLACE Function getIDArray
RETURN VARCHAR2 is
arr varchar2(1000);
CURSOR flux_to_process
IS
SELECT FLUX_ID, LOCKED_FLAG
FROM (
SELECT FLUX_ID, FLUX, GROUP_STORE_ID, STORE_ID, REFID, FLUX_TYPE, LOCKED_FLAG
FROM DEV_ISB_TRANSACTIONS.BUFFER_FLUX
WHERE status = 0
AND LOCKED_FLAG = 0
ORDER BY DATE_CREATION ASC)
WHERE ROWNUM <= 8;
BEGIN
FOR flux_rec IN flux_to_process
LOOP
IF flux_rec.LOCKED_FLAG = 0
THEN
UPDATE DEV_ISB_TRANSACTIONS.BUFFER_FLUX
SET LOCKED_FLAG = 1
WHERE FLUX_ID = flux_rec.FLUX_ID;
arr := flux_rec.FLUX_ID;
else exit;
COMMIT;
END IF;
END LOOP;
RETURN arr;
END;
The function compilation return an OK but i got no return of my values.
Do you guys have any clue to how to do this ?
Concerning your issue per se, the only two reasons I can see for the function to return "no value" would be either:
the SELECT part returns an empty set,
you have one record where FLUX_ID is NULL.
For improbable that could be that later option given the name of the column, it would be rather coherent with the fact that you override the result at each iteration -- and the ORDER BY orders NULL after not-NULL by default.

Creating a package to keep track of tapes used

Thought I had followed creation pattern, but the body will not compile. What I am trying to accomplish is to develop a package to run a procedrure periodically to determine at what time and date more than 15 are in use.. Oracle 11g.
The only other data that needs to go into the table beingg inserted into the sysdate.
CREATE OR REPLACE
PACKAGE TAPES_USED AS
function TAPESCOUNT(count number) return number;
procedure INSERT_TAPES_COUNT(sysdate date, count NUMBER);
END TAPES_USED;
/
-----------------------------------------
CREATE OR REPLACE
PACKAGE body TAPES_USED AS
function TAPESCOUNT(count number) return number as count number;
begin
select count(*)
into
count
from DEV.TAPES_IN USE where count(*) > 15;
procedure INSERT_TAPES_COUNT(sysdate date, count NUMBER)as
begin
INSERT INTO DEV.TAPES_USED VALUES
(sysdate, count);
end INSERT_TAPES_COUNT;
END TAPES_USED;
/
Any help or suggestion anyone can offer will be appreciated.
CREATE OR REPLACE
PACKAGE BODY tapes_used AS
FUNCTION tapescount(in_ct NUMBER) RETURN NUMBER IS
ct NUMBER;
BEGIN
SELECT COUNT(*)
INTO ct
FROM dev.tapes_in_use;
IF ct > in_ct THEN
RETURN ct;
ELSE
RETURN NULL;
END IF;
END tapescount;
PROCEDURE insert_tapes_count(sysdt date, ct NUMBER) IS
BEGIN
INSERT INTO dev.tapes_used VALUES (sysdt, ct);
END insert_tapes_count;
END tapes_used;
/
You should refrain from using reserved words such as COUNT and SYSDATE for variable names (I don't know but that could be some of your compilation issues), so I've renamed them. Also, you forgot to END your function. I think you were missing an underscore in your table name in the FROM clause of the SELECT in your function, and you didn't have a RETURN statement in your function, which you must have.
Generally speaking, a function should accept one or more input parameters and return a single value. You're not making use of the input parameter in your function. I've implemented a suggested parameter.
As Egor notes, this isn't a realistic function, and I'm not certain about your intent here. What is the function supposed to do?
Maybe you want your function to return the Date/Time your count was exceeded? You could also combine everything into a single procedure:
PROCEDURE ck_tape_ct(min_tape_ct NUMBER) IS
ct NUMBER;
BEGIN
SELECT COUNT(*)
INTO ct
FROM dev.tapes_in_use;
IF ct > min_tape_ct THEN
INSERT INTO dev.tapes_used VALUES(SYSDATE, ct);
END IF;
END;

Resources