Oracle SQL: how to pass parameter to a function that is used in a view through a column in a view? - sql

Let's say we have such view that uses function with hard-coded parameter:
CREATE OR REPLACE VIEW x AS
SELECT t.some_value
FROM table(function(p1 => '1')) t;
If I'd like to pass that parameter to a function through a view, what are possible options? Please mind that using global or context/bind variables is not an option. So far I've came up with an option to use a table that holds all available parameter values (keys) that could be passed to a view:
CREATE OR REPLACE VIEW x AS
SELECT st.input_param,
t.some_value
FROM some_table st
table(function(p1 => st.input_param)) t;
However, I am wondering if there are any other possible options?

You can't pass a parameter to a view but you can use the next alternative:
CREATE TYPE RECORDS_VARCHAR AS TABLE OF VARCHAR2(100);
create or replace function virtual_table( input_param number )
return RECORDS_VARCHAR
PIPELINED
is
begin
FOR a IN (
select '1' AS VALUE from dual where input_param = 2
UNION ALL
select '8' AS VALUE from dual
) loop
pipe row (a.VALUE);
end loop;
return;
end;
SELECT * FROM TABLE(virtual_table(2)); --1,8
SELECT * FROM TABLE(virtual_table(1)); --8

Related

how to add two parameters and get value in sql (convert code pl/sql to sql )

function CF_TOTAL_AMTFormula return Number is
begin
RETURN NVL(:AMOUNT,0)+ NVL(:CF_TAX,0);
end;
This function is created in PL/SQL and I want to create this function in SQL.
As OldProgrammer mentioned above, "SQL does not have user-defined functions". Maybe you just want to add two parameters together in SQL? It's pretty straightforward...
select NVL(:AMOUNT,0) + NVL(:CF_TAX,0) as CF_TOTAL_AMT from dual;
Well, SQL does allow inline functions, but they are implemented in PL/SQL so I'm not sure whether they meet your requirement:
with function cf_total_amtformula
( amount number, cf_tax number )
return number
as
begin
return nvl(amount,0) + nvl(cf_tax,0);
end;
select amount, cf_tax
, cf_total_amtformula(amount, cf_tax) as formula_result
from -- inline view to provide demo data:
( select 123 as amount, .2 as cf_tax from dual
union all
select 123, null from dual
union all
select null, .2 from dual )
(requires Oracle 12.1 or later.)
Obviously you could just use nvl(amount,0) + nvl(cf_tax,0) directly without defining any function, or define a column in a view etc.
Putting Bind parameters into a function definition doesn't work, and results in a PLS-00049: bad bind variable error. I think what you are looking for is this:
function CF_TOTAL_AMTFormula(AMOUNT number, CF_TAX number) return Number is
begin
RETURN NVL(AMOUNT,0)+ NVL(CF_TAX,0);
end;
Note that both AMOUNT and CF_TAX have had the leading colons : removed, and have been moved up to the function signature.
Once compiled with create or replace ... you can then call the function in SQL like so:
select CF_TOTAL_AMTFormula(121, 12.1) from dual;
select amount, cf_tax
, nvl(amount,0) + nvl(cf_tax,0)
from -- inline view to provide demo data:
( select 123 as amount, .2 as cf_tax from dual
union all
select 123, null from dual
union all
select null, .2 from dual )

Oracle function with select all from tables

SELECT DISTINCT L.* FROM LABALES L , MATCHES M
WHERE M.LIST LIKE '%ENG'
ORDER BY L.ID
I need to create function with this select, I tried this but it doesn't work.
CREATE OR REPLACE FUNCTION getSoccerLists
RETURN varchar2 IS
list varchar2(2000);
BEGIN
SELECT DISTINCT L.* FROM LABALES L , MATCHES M
WHERE M.LIST LIKE '%ENG'
ORDER BY L.ID
return list;
END;
How will I create function that returns all from table L.
Thanks
You may use implicit result using DBMS_SQL.RETURN_RESULT(Oracle12c and above) in a procedure using a cursor to your query.
CREATE OR REPLACE PROCEDURE getSoccerLists
AS
x SYS_REFCURSOR;
BEGIN
OPEN x FOR SELECT DISTINCT L.* FROM LABALES L
JOIN MATCHES M ON ( 1=1 ) -- join condition
WHERE M.LIST LIKE '%ENG'
ORDER BY L.ID;
DBMS_SQL.RETURN_RESULT(x);
END;
/
then simply call the procedure
EXEC getSoccerLists;
For lower versions(Oracle 11g) , you may use a print command to display the cursor's o/p passing ref cursor as out parameter.
CREATE OR REPLACE PROCEDURE getSoccerLists (x OUT SYS_REFCURSOR)
AS
BEGIN
OPEN x FOR SELECT DISTINCT L.* FROM LABALES L
JOIN MATCHES M ON ( 1=1 ) -- join condition
WHERE M.LIST LIKE '%ENG'
ORDER BY L.ID;
END;
/
Then, in SQL* Plus or running as script in SQL developer and Toad, you may get the results using this.
VARIABLE r REFCURSOR;
EXEC getSoccerLists (:r);
PRINT r;
Another option is to use TABLE function by defining a collection of the record type of the result within a package.
Refer Create an Oracle function that returns a table
I guess this questions is a repetition of the your previously asked question, where you wanted to get all the columns of tables but into separate column. I already answered in stating this you cannot do if you call your function via a SELECT statement. If you call your function in a Anoymous block you can display it in separate columns.
Here Oracle function returning all columns from tables
Alternatively, you can get the results separated by a comma(,) or pipe (|) as below:
CREATE OR REPLACE
FUNCTION getSoccerLists
RETURN VARCHAR2
IS
list VARCHAR2(2000);
BEGIN
SELECT col1
||','
||col2
||','
||col2
INTO LIST
FROM SOCCER_PREMATCH_LISTS L ,
SOCCER_PREMATCH_MATCHES M
WHERE M.LIST LIKE '%' || (L.SUB_LIST) || '%'
AND (TO_TIMESTAMP((M.M_DATE || ' ' || M.M_TIME), 'DD.MM.YYYY HH24:MI') >
(SELECT SYSTIMESTAMP AT TIME ZONE 'CET' FROM DUAL
))
ORDER BY L.ID");
Return list;
End;
Note here if the column size increased 2000 chars then again you will lose the data.
Edit:
From your comments
I want it to return a table set of results.
You then need to create a table of varchar and then return it from the function. See below:
CREATE TYPE var IS TABLE OF VARCHAR2(2000);
/
CREATE OR REPLACE
FUNCTION getSoccerLists
RETURN var
IS
--Initialization
list VAR :=var();
BEGIN
SELECT NSO ||',' ||NAME BULK COLLECT INTO LIST FROM TEST;
RETURN list;
END;
Execution:
select * from table(getSoccerLists);
Note: Here in the function i have used a table called test and its column. You replace your table with its columnname.
Edit 2:
--Create a object with columns same as your select statement
CREATE TYPE v_var IS OBJECT
(
col1 NUMBER,
col2 VARCHAR2(10)
)
/
--Create a table of your object
CREATE OR REPLACE TYPE var IS TABLE OF v_var;
/
CREATE OR REPLACE FUNCTION getSoccerLists
RETURN var
IS
--Initialization
list VAR :=var();
BEGIN
--You above object should have same columns with same data type as you are selecting here
SELECT v_var( NSO ,NAME) BULK COLLECT INTO LIST FROM TEST;
RETURN list;
END;
Execution:
select * from table(getSoccerLists);
This is not an answer on how to build a function for this, as I'd recommend to make this a view instead:
CREATE OR REPLACE VIEW view_soccer_list AS
SELECT *
FROM soccer_prematch_lists l
WHERE EXISTS
(
SELECT *
FROM soccer_prematch_matches m
WHERE m.list LIKE '%' || (l.sub_list) || '%'
AND TO_TIMESTAMP((m.m_date || ' ' || m.m_time), 'DD.MM.YYYY HH24:MI') >
(SELECT SYSTIMESTAMP AT TIME ZONE 'CET' FROM DUAL)
);
Then call it in a query:
SELECT * FROM view_soccer_list ORDER BY id;
(It makes no sense to put an ORDER BY clause in a view, because you access the view like a table, and table data is considered unordered, so you could not rely on that order. The same is true for a pipelined function youd access with FROM TABLE (getSoccerLists). Always put the ORDER BY clause in your final queries instead.)

How to return multiple values from a function without global types

In an application GUI-Elements can be initialized by using SQL statements.
SELECT name $GUIElement
FROM myTable
WHERE id = 1337;
Since the underlying database structure may change, I am prefering to hide the structure and use an Oracle Package as interface instead. For single values this approach works well with functions like:
SELECT myPackage.getNameByID(1337) $GUIElement
FROM DUAL;
Now I am facing the issue of initializing a list. Original Code:
SELECT name $GUIList
FROM myTable;
To return multiple values from a function I need to define a new SQL type. If the function returns a TABLE OF VARCHAR2 this code works:
SELECT COLUMN_VALUE $GUIList
FROM TABLE(myPackage.getNames())
Unfortunately, I have no rights to create new types on the productive database.
So, is there a way in Oracle to get a similar behaviour without defining a new data type? I have looked into SYS_REFCURSERbut it seems not to work properly.
What about xmltype. The function always returns xml type. And for processing this object you are using xmltable.
Something like this.
create or replace function return_params return xmltype is
result xmltype;
begin
select xmlelement(params,xmlagg(xmlelement(param,xmlforest(name,value,data_type)))) into result from (
select 'param_name1' name, 'param_value1' value , 'varchar2' data_type from dual
union all
select 'param_name2' name, 'param_value2' value , 'varchar2' data_type from dual
union all
select 'param_name3' name, 'param_value3' value , 'varchar2' data_type from dual
); return result;
end;
select * from xmltable('/PARAMS/PARAM' passing return_params
columns name varchar2(1000) path 'NAME'
,value varchar2(1000) path 'VALUE'
,data_type varchar2(1000) path 'DATA_TYPE'
)

How to call pl-sql function that takes table of numbers as input with 1 number?

I have a function that takes table of Numbers as an input:
function foo(ids in custom_array)...
where custom_array is a table of Numbers.
How do I call this function from SQL query if I need to pass only 1 parameter?
I supposed that this should look like this
select * from table(foo(123))
but my guess was wrong.
edit:
function's declaration looks like this:
create or replace function foo(id in custom_array) return
tableof2numbers AS
mytable tableof2numbers;
BEGIN
SELECT cast(
MULTISET (
/*there goes some super secret business logic*/
/*let's say that here we just do smth like this: */
select 123, 123 from dual
/*because this is not so important for this question*/
)
AS tableof2numbers)
INTO
mytable
FROM dual;
RETURN mytable;
where tableof2numbers is another custom type which declaration is pretty similar to custom_array, but with 2 numbers.
Thanks in advance!!!
My example:
1) TYPE
create or replace TYPE "TABLE_OF_NUMBER"
AS TABLE OF NUMBER
2) FUNCTION
CREATE OR REPLACE FUNCTION foo(
par IN table_of_number)
RETURN NUMBER
IS
BEGIN
RETURN par(1);
END;
3) SELECT
SELECT foo(table_of_number(123)) FROM dual
If your function returns table, it will be something like
SELECT * FROM TABLE (foo(custom_array(123)))
Hope it will help.

PL/SQL - Returning a table from a function

I am creating a function that returns a table as a result. This function is basically doing comparison between two tables, and returns data set that if two tables contain different data.
P_min_id and p_max_id are ignorable, and will be implemented in the future once this function is working.
I modified the original code from http://www.adp-gmbh.ch/ora/plsql/coll/return_table.html. The error messages are commented in the following code.
create or replace function return_objects(
p_min_id in number,
p_max_id in number
)
return t_nested_table as
v_ret t_nested_table;
begin
select * // Error(8,7): PL/SQL: SQL Statement ignored
into
v_ret
from
(
select
*
from
(
select * from
(
select * from SCHEMA.TEST
minus
select * from SCHEMA.TEST_1
)
union all
select * from
(
select * from SCHEMA.TEST_1
minus
select * from SCHEMA.TEST
)
)
)
return v_ret;
end return_objects;
It would be appreciated if you can fix my code, but I want to know why this code should not work. Please give me some keyword, so that I can research. or relevant website for reference would be also appreciated.
Add a semicolon after the end of the SQL statement and use bulk collect to populate the nested table. Here's a working example:
create or replace type t_nested_table is table of varchar2(100);
create or replace function return_objects(
p_min_id in number,
p_max_id in number
)
return t_nested_table as
v_ret t_nested_table;
begin
select *
bulk collect into v_ret
from
(
select 'A' from dual union all
select 'B' from dual
);
return v_ret;
end;
/
select return_objects(1,2) from dual;
UPDATE
Based on the question edits there is also a privilege issue. Your user probably has access to the tables through a role, but to create a function those privileges should be granted directly to your user.