Oracle function with select all from tables - sql

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.)

Related

convert varchar value to array to varchar sql oracle [duplicate]

I am having trouble getting a block of pl/sql code to work. In the top of my procedure I get some data from my oracle apex application on what checkboxes are checked. Because the report that contains the checkboxes is generated dynamically I have to loop through the
APEX_APPLICATION.G_F01
list and generate a comma separated string which looks like this
v_list VARCHAR2(255) := (1,3,5,9,10);
I want to then query on that list later and place the v_list on an IN clause like so
SELECT * FROM users
WHERE user_id IN (v_list);
This of course throws an error. My question is what can I convert the v_list to in order to be able to insert it into a IN clause in a query within a pl/sql procedure?
If users is small and user_id doesn't contain commas, you could use:
SELECT * FROM users WHERE ',' || v_list || ',' LIKE '%,'||user_id||',%'
This query is not optimal though because it can't use indexes on user_id.
I advise you to use a pipelined function that returns a table of NUMBER that you can query directly. For example:
CREATE TYPE tab_number IS TABLE OF NUMBER;
/
CREATE OR REPLACE FUNCTION string_to_table_num(p VARCHAR2)
RETURN tab_number
PIPELINED IS
BEGIN
FOR cc IN (SELECT rtrim(regexp_substr(str, '[^,]*,', 1, level), ',') res
FROM (SELECT p || ',' str FROM dual)
CONNECT BY level <= length(str)
- length(replace(str, ',', ''))) LOOP
PIPE ROW(cc.res);
END LOOP;
END;
/
You would then be able to build queries such as:
SELECT *
FROM users
WHERE user_id IN (SELECT *
FROM TABLE(string_to_table_num('1,2,3,4,5'));
You can use XMLTABLE as follows
SELECT * FROM users
WHERE user_id IN (SELECT to_number(column_value) FROM XMLTABLE(v_list));
I have tried to find a solution for that too but never succeeded. You can build the query as a string and then run EXECUTE IMMEDIATE, see http://docs.oracle.com/cd/B19306_01/appdev.102/b14261/dynamic.htm#i14500.
That said, it just occurred to me that the argument of an IN clause can be a sub-select:
SELECT * FROM users
WHERE user_id IN (SELECT something FROM somewhere)
so, is it possible to expose the checkbox values as a stored function? Then you might be able to do something like
SELECT * FROM users
WHERE user_id IN (SELECT my_package.checkbox_func FROM dual)
Personally, i like this approach:
with t as (select 'a,b,c,d,e' str from dual)
--
select val
from t, xmltable('/root/e/text()'
passing xmltype('<root><e>' || replace(t.str,',','</e><e>')|| '</e></root>')
columns val varchar2(10) path '/'
)
Which can be found among other examples in Thread: Split Comma Delimited String Oracle
If you feel like swamping in even more options, visit the OTN plsql forums.

SQL - Call a proc or function where user enters two table names

I cannot seem to find an answer for my question or even if its possible, I want to create a function or procedure that asks the user for two table names something like Table A and Table B
call myfunction(table_a, table_b)
or
call myprocedure(table_a, table_b)
inside each table contains addresses and i've created a script to tear the address to parts and try to match them together, but i only want to produce the call function above.
each table structure would have the same structure
SELECT * FROM (SELECT KEY_A
,ADDRESS_LINE
,POSTCODE
,ROW_NUMBER() OVER(PARTITION BY KEY_A ORDER BY ADDRESS_LINE) ADDRESS_LINE_RN
FROM TABLE_NAME) A
WHERE ADDRESS_LINE_RN = 1 AND LENGTH(TRIM(ADDRESS_LINE)) > 0 AND LENGTH(TRIM(POSTCODE)) > 0
Is this even possible? I just want to keep the end user experience easy and fast.
Many Thanks
create or replace procedure select_table (name1 varchar2) is
begin
execute immediate 'select * from '||name1;
end;
Here is the code but u wont see any output u need to put the result in a variable or in a collection and then loop through collection to output the result, or u can create a pipelined table function like this:
CREATE OR REPLACE FUNCTION select_table (name1 VARCHAR2)
RETURN YOUR_OBJECT%ROWTYPE PIPELINED IS
TYPE t_sql_result IS
TABLE OF your_object%rowtype INDEX BY PLS_INTEGER;
sql_result t_sql_result;
BEGIN
EXECUTE IMMEDIATE
'SELECT * FROM (SELECT KEY_A ,ADDRESS_LINE ,POSTCODE ,ROW_NUMBER()
OVER(PARTITION BY KEY_A ORDER BY ADDRESS_LINE) ADDRESS_LINE_RN FROM '||name1||')
A WHERE ADDRESS_LINE_RN = 1 AND LENGTH(TRIM(ADDRESS_LINE)) > 0 AND LENGTH(TRIM(POSTCODE)) > 0'
BULK COLLECT INTO sql_result;
FOR I IN sql_result.FIRST..sql_result.LAST LOOP
PIPE ROW (T_sql_result(I.FIRST_COLUMN,I.SECOND_COLUMN...));
END LOOP;
RETURN;
END;
SELECT * FROM TABLE(select_table('table_name'));

Oracle SQL Create function or procedure returning a table

In SQL Server, I can just use 'RETURNS TABLE' and it will do the job. But I can't find how to do the same in Oracle SQL
I have the following SELECT statement that needs to be put in a function or procedure:
SELECT a.CodAcord, a.Descr
FROM FreqSoce f
LEFT JOIN Acord a ON a.CodAcord = f.CodAcord
WHERE f.codSoce = codSoce;
codSoce is an INTEGER IN parameter, and I need to return a.CodAcord and a.Descr as result from my function/procedure.
Is there a simple way to do this? Without having to deal with temp variables and/or advanced content...
EDIT: Aditional info:
- I need to return a.CodAcord and a.Descr, but when I did some research to know how to return more than one variable using SQL Functions or Procedures, all I could find was that this was only possible by returning a TABLE. If there's a way to return more than one item from a Function or Procedure, please let me know.
- The use of Functions or Procedures is strictly required.
- I'm using SQL Developer.
You can achieve a table as a return value from function by using a pipelined table function. Please see the example below:
-- Create synthetic case
CREATE TABLE Acord AS
SELECT rownum CodAcord, 'Description ' || rownum Descr
FROM dual CONNECT BY LEVEL <= 5;
CREATE TABLE FreqSoce AS
SELECT rownum CodSoce, rownum CodAcord
FROM dual CONNECT BY LEVEL <= 10;
-- Test dataset
SELECT a.CodAcord, a.Descr
FROM FreqSoce f
LEFT JOIN Acord a ON a.CodAcord = f.CodAcord
WHERE f.CodSoce = 10;
-- Here begins actual code
-- Create an object type to hold each table row
CREATE OR REPLACE TYPE typ_acord AS OBJECT(
CodAcord NUMBER,
Descr VARCHAR2(40)
);
/
-- Create a collection type to hold all result set rows
CREATE OR REPLACE TYPE tab_acord AS TABLE OF typ_acord;
/
-- Our function that returns a table
CREATE OR REPLACE FUNCTION getAcord(pCodSoce IN NUMBER)
RETURN tab_acord PIPELINED
AS
BEGIN
FOR x IN (SELECT a.CodAcord, a.Descr
FROM FreqSoce f
LEFT JOIN Acord a ON a.CodAcord = f.CodAcord
WHERE f.CodSoce = pCodSoce)
LOOP
PIPE ROW (typ_acord(x.CodAcord, x.Descr));
END LOOP;
END;
/
-- Testing the function (please note the TABLE operator)
SELECT * FROM TABLE(getAcord(5));
Take the following as a code template:
CREATE OR REPLACE PACKAGE tacord AS
TYPE ttabAcord IS TABLE OF ACord%ROWTYPE;
END tacord;
/
show err
CREATE OR REPLACE PACKAGE BODY tacord AS
BEGIN
NULL;
END tacord;
/
show err
CREATE OR REPLACE FUNCTION demo RETURN tacord.ttabAcord AS
to_return tacord.ttabAcord;
BEGIN
SELECT a.*
BULK COLLECT INTO to_return
FROM FreqSoce f
LEFT JOIN Acord a ON a.CodAcord = f.CodAcord
WHERE f.codSoce = codSoce
;
RETURN to_return;
END demo;
/
show err
Key points:
%ROWTYPE represents the datatype of a database table's record
BULK COLLECT INTO inserts a complete result set into a plsql data structure
Iteration over the table contents is availabel by the plsql collection methods, namely .FIRST, .LAST, .NEXT.

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.

nzsql - Converting a subquery into columns for another select

Goal: Use a given subquery's results (a single column with many rows of names) to act as the outer select's selection field.
Currently, my subquery is the following:
SELECT column_name
FROM information_schema.columns
WHERE table_name = 'test_table' AND column_name not in ('colRemove');
What I am doing in this subquery is grabbing all the column names from a table (i.e. test_table) and outputting all except for the column name specified (i.e. colRemove). As stated in the "goal", I want to use this subquery as such:
SELECT (*enter subquery from above here*)
FROM actual_table
WHERE (*enter specific conditions*)
I am working on a Netezza SQL server that is version 7.0.4.4. Ideally, I would like to make the entire query executable in one line, but for now, a working solution would be much appreciated. Thanks!
Note: I do not believe that the SQL extensions has been installed (i.e. arrays), but I will need to double check this.
A year too late, here's the best I can come up with but, as you already noticed, it requires a stored procedure to do the dynamic SQL. The stored proc creates a view with the all the columns from the source table minus the one you want to exclude.
-- Create test data.
CREATE TABLE test (firstcol INTEGER, secondcol INTEGER, thirdcol INTEGER);
INSERT INTO test (firstcol, secondcol, thirdcol) VALUES (1, 2, 3);
INSERT INTO test (firstcol, secondcol, thirdcol) VALUES (4, 5, 6);
-- Install stored procedure.
CREATE OR REPLACE PROCEDURE CreateLimitedView (varchar(ANY), varchar(ANY)) RETURNS BOOLEAN
LANGUAGE NZPLSQL AS
BEGIN_PROC
DECLARE
tableName ALIAS FOR $1;
columnToExclude ALIAS FOR $2;
colRec RECORD;
cols VARCHAR(2000); -- Adjust as needed.
isfirstcol BOOLEAN;
BEGIN
isfirstcol := true;
FOR colRec IN EXECUTE
'SELECT ATTNAME AS NAME FROM _V_RELATION_COLUMN
WHERE
NAME=UPPER('||quote_literal(tableName)||')
AND ATTNAME <> UPPER('||quote_literal(columnToExclude)||')
ORDER BY ATTNUM'
LOOP
IF isfirstcol THEN
cols := colRec.NAME;
ELSE
cols := cols || ', ' || colRec.NAME;
END IF;
isfirstcol := false;
END LOOP;
-- Should really check if 'LimitedView' already exists as a view, table or synonym.
EXECUTE IMMEDIATE 'CREATE OR REPLACE VIEW LimitedView AS SELECT ' || cols || ' FROM ' || quote_ident(tableName);
RETURN true;
END;
END_PROC
;
-- Run the stored proc to create the view.
CALL CreateLimitedView('test', 'secondcol');
-- Select results from the view.
SELECT * FROM limitedView WHERE firstcol = 4;
FIRSTCOL | THIRDCOL
----------+----------
4 | 6
You could have the stored proc return a resultset directly but then you wouldn't be able to filter results with a WHERE clause.