I have a function with parameters of numerical type, I have done the query successfully, my problems is that I do not know how to pass several parameters within the IN, where id in(parameter).
The id is of type BIGINT
From JAVA I have the following query:
select parametro1, parametro2, parametro3 from function_detalls ("parameters");
Where parameters is a string type 1,2,3,4,5,6,7, ....
My question is how can I pass this type of parameter to the function?
Pass an array to your function and use WHERE = ANY().
For example:
CREATE FUNCTION func_test(params text[])
RETURNS SETOF test
LANGUAGE PLPGSQL
AS $$
DECLARE
BEGIN
RETURN QUERY
SELECT * FROM test WHERE txt = ANY(params);
END;
$$
To call:
SELECT * FROM func_test(ARRAY['hello', 'world']);
DBFiddle to show it in action
Related
How can I return a set of data from PL/SQL?
I have a stored procedure that needs to run a select statement and returns the result back to the calling (Java) program.
The select statement comprises of a few joins from multiple tables, so I am not sure how to define this type in the stored procedure definition or body.
I was thinking maybe this can be done as following, but SQL Developer is giving me errors:
CREATE OR REPLACE PACKAGE my_package
AS
TYPE a_collection_records IS RECORD (
NUMBER FIRST_COL,
VARCHAR2 SECOND_COL -- a few others
);
-- Procedure API that uses a_collection_records type
END;
CREATE OR REPLACE PROCEDURE sample_procedure(
p_some_select_sql_result OUT my_package.a_collection_records
)
AS
BEGIN
-- Populate p_some_select_sql_result with some select data
END;
Unless you are particularly set on using a collection, it would be simpler to use a ref cursor:
CREATE OR REPLACE PROCEDURE sample_procedure (
p_some_select_sql_result OUT SYS_REFCURSOR
)
AS
BEGIN
OPEN p_some_select_sql_result FOR
SELECT ...
FROM ...
JOIN ...
... etc.;
END;
/
From JDBC you can then do something like:
cStmt = conn.prepareCall('{ call sample_procedure(?) }');
cStmt.registerOutParameter(1, oracle.jdbc.OracleTypes.CURSOR);
cStmt.execute();
rSet = cStmt.getCursor(1);
and you can then iterate over the result set as you would with any other.
You could also use a function instead:
CREATE OR REPLACE FUNCTION sample_function RETURN SYS_REFCURSOR
AS
l_some_select_sql_result
BEGIN
OPEN l_some_select_sql_result FOR
SELECT ...
FROM ...
JOIN ...
... etc.;
RETURN l_some_select_sql_result;
END;
/
and
cStmt = conn.prepareCall('{ ?=call sample_function }');
cStmt.registerOutParameter(1, oracle.jdbc.OracleTypes.CURSOR);
cStmt.execute();
rSet = cStmt.getCursor(1);
Obviously you need to handle any other parameters you're passing to your real procedure/function.
Your type definition is a little bit out of order. You have the type definition before the name of the item.
TYPE a_collection_records IS RECORD (
NUMBER FIRST_COL,
VARCHAR2 SECOND_COL -- a few others
);
It should be
TYPE a_collection_records IS RECORD (
FIRST_COL NUMBER,
SECOND_COL VARCHAR2 -- a few others
);
The name of the column comes before the column's datatype. I hope this is what you are looking for. You could always do a refcursor, but if you want names that are not the actual column names on the tables you are selecting from then you will still what a record type.
To be able to create it as a custom set just declare after the close of the RECORD definition the following line of code
TYPE collection_list IS TABLE a_collection_records;
Complete example:
TYPE a_collection_records IS RECORD (
FIRST_COL NUMBER,
SECOND_COL VARCHAR2 -- a few others
);
TYPE collection_list IS TABLE OF a_collection_records;
That will give you a custom (and column masked) set of data.
MSSQL has a great feature called Table Valued Parameters. It allows you to pass a table of a custom data to stored procedures and functions.
I was wondering what is the equivalent in PostgreSQL, if one exists, using JDBC?
I know about the option of passing arrays as function parameters, but that seems limited to PostgreSQL data types.
Consider the following PL/pgSQL code:
CREATE TYPE number_with_time AS(
_num float,
_date timestamp
);
and this function header:
CREATE OR REPLACE FUNCTION myfunc(arr number_with_time[])
Can anyone post a Java code using JDBC driver of calling that function with an array of the user defined data type?
Assuming you want to pass values from the client. If the values exist in the database already there are other, simpler ways.
Syntax for array of composite_type
I know about the option of passing arrays as function parameters, but
that seems limited to PostgreSQL data types.
What you can pass seems to be limited by Java Types and JDBC Types, and there does not seem be provisions for array types, not to speak of arrays of composite values ...
However, you can always pass a text representation. I am building on two basic facts:
Quoting the manual:
Arrays of any built-in or user-defined base type, enum type, or
composite type can be created. Arrays of domains are not yet supported.
Bold emphasis mine. Therefore, after you have created the type number_with_time as defined in your question, or defined a table with the same columns which registers the row type in the system automatically, you can also use the array type number_with_time[].
There is a text representation for every value.
Therefore, there is also a text representation for number_with_time[]:
'{"(1,2014-04-20 20:00:00)","(2,2014-04-21 21:00:00)"}'::number_with_time[]
Function call
The actual function call depends on the return values defined in your function - which is hidden in your question.
To avoid complications from array handling in JDBC, pass the text representation. Create the function taking a text parameter.
I am not going to use the name "date" for a timestamp. Working with this slightly adjusted type definition:
CREATE TYPE number_with_time AS(
_num float
, _ts timestamp
);
Simple SQL function:
CREATE OR REPLACE FUNCTION myfunc_sql(_arr_txt text)
RETURNS integer -- example
LANGUAGE sql AS
$func$
SELECT sum(_num)::int
FROM unnest (_arr_txt::number_with_time[]) x
WHERE _ts > '2014-04-19 20:00:00';
$func$;
Call:
SELECT myfunc_sql('{"(1,2014-04-20 20:00:00)","(2,2014-04-21 21:00:00)"}');
db<>fiddle here
Old sqlfiddle
Demonstrating:
above SQL function
PL/pgSQL variant
a couple of syntax variants for the array of composite type
the function calls
Call the function like any other function taking a simple text parameter:
CallableStatement myProc = conn.prepareCall("{ ? = call myfunc_sql( ? ) }");
myProc.registerOutParameter(1, Types.VARCHAR);
// you have to escape double quotes in a Java string!
myProc.setString(2, "{\"(1,2014-04-20 20:00:00)\",\"(2,2014-04-21 21:00:00)\"}");
myProc.execute();
String mySum = myProc.getInt(1);
myProc.close();
Details in the Postgres JDBC manual here.
Example to return a whole table via JDBC:
Return rows from a PL/pgSQL function
Try something like this:
------------------ your connection
V
Array inArray = conn.createArrayOf("integer", new Integer[][] {{1,10},{2,20}});
stmt.setArray(1, inArray);
A sample method you could use to build your test:
public void testInsertMultiDimension() throws Exception {
Connection c = getConnection();
PreparedStatement stmt = c.prepareStatement("INSERT INTO sal_emp VALUES ('multi_Bill',?,?);");
Array intArray = c.createArrayOf("integer", new Integer[] {1000,1000,1000,1000});
String[][] elements = new String[2][];
elements[0] = new String[] {"meeting_m","lunch_m"};
elements[1] = new String[] {"training_m","presentation_m"};
//Note - although this is a multi-dimensional array, we still supply the base element of the array
Array multiArray = c.createArrayOf("text", elements);
stmt.setArray(1, intArray);
stmt.setArray(2, multiArray);
stmt.execute();
//Note - free is not implemented
//myArray.free();
stmt.close();
c.close();
}
Helpful links:
Binding parameter as PostgreSQL array
Postgres and multi-dimensions arrays in JDBC
Passing Array from Java to Postgres
Your problem is PostgreSQL can use table or complex type as function's parameter or "table or complex type"'s array as function's paramter?
postgresql all support. and when you create a table, it's auto create an complex type named same as tablename.
like :
digoal=# create table tbl123(id int, info text);
CREATE TABLE
digoal=# select typname from pg_type where typname='tbl123';
typname
---------
tbl123
(1 row)
and you can use this type in function direct.
for exp :
digoal=# create or replace function f_tbl123(i tbl123) returns tbl123 as $$
declare
begin
return i;
end;
$$ language plpgsql;
CREATE FUNCTION
digoal=# insert into tbl123 values (1,'test'),(2,'test2');
INSERT 0 2
digoal=# select f_tbl123(t) from tbl123 t;
f_tbl123
-----------
(1,test)
(2,test2)
(2 rows)
the array is also can used in postgresql function.
if you don't known how array construct in java, i think this exp can help you.
digoal=# select (unnest('{"(1,abc)","(2,ww)"}'::tbl123[])).*;
id | info
----+------
1 | abc
2 | ww
(2 rows)
digoal=# select '{"(1,abc)","(2,ww)"}'::tbl123[];
tbl123
----------------------
{"(1,abc)","(2,ww)"}
(1 row)
digoal=# select array['(1,abc)','(2,ww)'];
array
----------------------
{"(1,abc)","(2,ww)"}
(1 row)
digoal=# select array['(1,abc)','(2,ww)']::tbl123[];
array
----------------------
{"(1,abc)","(2,ww)"}
(1 row)
digoal=# select (unnest(array['(1,abc)','(2,ww)'])::tbl123).*;
id | info
----+------
1 | abc
2 | ww
(2 rows)
I'm trying to pass an array as a String in MySQL Stored Procedure but it doesn't work fine.
Here's my SQL Codes:
CREATE DEFINER=`root`#`localhost` PROCEDURE `search_equipment`(IN equip VARCHAR(100), IN category VARCHAR(255))
BEGIN
SELECT *
FROM Equipment
WHERE e_description
LIKE CONCAT("%",equip,"%")
AND e_type IN (category)
END
And here's how i call the procedure:
String type = "'I.T. Equipment','Office Supply'";
CALL search_equipment('some equipment', type);
Any ideas?
Your friend here is FIND_IN_SET I expect. I first came across that method in this question : also covered in this question MYSQL - Stored Procedure Utilising Comma Separated String As Variable Input
MySQL documention for FIND_IN_SET is here http://dev.mysql.com/doc/refman/5.0/en/string-functions.html#function_find-in-set
So your procedure will become
CREATE DEFINER=`root`#`localhost`
PROCEDURE `search_equipment`(
IN equip VARCHAR(100),
IN category VARCHAR(255)
)
BEGIN
SELECT *
FROM Equipment
WHERE e_description LIKE CONCAT("%",equip,"%")
AND FIND_IN_SET(e_type,category)
END
This relies on the category string being a comma-delimited list, and so your calling code becomes
String type = "I.T. Equipment,Office Supply";
CALL search_equipment('some equipment', type);
(p.s. fixed a typo, in your arguments you had typed categoy)
you have to create a dynamic statment:
DELIMITER $$
CREATE DEFINER=`root`#`localhost` PROCEDURE `search_equipment`(IN equip VARCHAR(100), IN category VARCHAR(255))
BEGIN
SET #s =
CONCAT('SELECT *
FROM Equipment
WHERE e_description
LIKE \'%',equip,'%\'
AND e_type IN (',category,')');
PREPARE stmt from #s;
EXECUTE stmt;
DEALLOCATE PREPARE stmt3;
END$$
This helps for me to do IN condition
Hope this will help you..
CREATE PROCEDURE `test`(IN Array_String VARCHAR(100))
BEGIN
SELECT * FROM Table_Name
WHERE FIND_IN_SET(field_name_to_search, Array_String);
END//;
Calling:
call test('3,2,1');
I have a stored procedure which returns sys_refcursor and I am trying to fetch the cursor from java using JDBC.
plsql stored procedure
create or replace procedure my_proc(p_deptno IN number,p_emp_no IN varchar2
, p_cursor OUT SYS_REFCURSOR)
is
begin
open p_cursor FOR
select *
from emp
where deptno = p_deptno and emp_number=p_emp_no;
end proc;
/
java code
callablestatement = connection.prepareCall("{cal my_proc(?,?,?)} ");
callablestatement.setInt(1, param1);
callablestatement.setString(2, param2);
callablestatement.registerOutParameter(3, OracleTypes.CURSOR);
callablestatement.execute();
resultSet = ((OracleCallableStatement)callablestatement).getCursor(4);
while (resultSet.next()) {
<classname> = mapList(resultSet);
logger.info(resultSet.getString(1));
}
When I execute the above I am getting the following execeptions
java.lang.NullPointerException at callablestatement.execute();
and
Non supported SQL92 token at position: 3: cal
You have a typo in your statement:
{cal my_proc(?,?,?)}
should be
{call my_proc(?,?,?)}
use theCallableStatement.setObject( instead
Of
.setString and .setInt etc
it has also theCallableStatement.setNull for null
but keep registerOutParameter the same
description for the method
Sets the value of the designated parameter with the given object. The
second parameter must be of type Object; therefore, the java.lang
equivalent objects should be used for built-in types. The JDBC
specification specifies a standard mapping from Java Object types to
SQL types. The given argument will be converted to the corresponding
SQL type before being sent to the database. Note that this method may
be used to pass datatabase- specific abstract data types, by using a
driver-specific Java type. If the object is of a class implementing
the interface SQLData, the JDBC driver should call the method
SQLData.writeSQL to write it to the SQL data stream. If, on the other
hand, the object is of a class implementing Ref, Blob, Clob, NClob,
Struct, java.net.URL, or Array, the driver should pass it to the
database as a value of the corresponding SQL type. This method throws
an exception if there is an ambiguity, for example, if the object is
of a class implementing more than one of the interfaces named above.
Note: Not all databases allow for a non-typed Null to be sent to the
backend. For maximum portability, the setNull or the setObject(String
parameterName, Object x, int sqlType) method should be used instead of
setObject(String parameterName, Object x).
I have resolved the issue by using a function with the same code as in the procedure and it has resolved my issue.
And I called my function using the following manner.
private final String FUNCTIONAME= "begin ? :=myfunc(?,?,?); end;"";
Thanks
I'm trying to call a PostgreSQL stored procedure from a Java app; the procedure has a DATE type parameter so I'm using a java.sql.Date type with CallableStatement.setDate(). However, executing the statement always results in an exception and the SQL logs show this:
LOG: execute <unnamed>: select * from athlete.create_athlete($1,$2,$3,$4,$5,$6,$7) as result
DETAIL: parameters: $1 = '', $2 = 'foo#bar.com', $3 = 'Joe', $4 = 'Blow', $5 = 'foobar', $6 = 'M', $7 = '1979-03-22 -04:00:00'
ERROR: column "dob" is of type date but expression is of type text at character 122
HINT: You will need to rewrite or cast the expression.
QUERY: INSERT INTO athlete.athlete (email, first_name, last_name, password, gender, dob) VALUES ( $1 , $2 , $3 , $4 , $5 , $6 )
CONTEXT: PL/pgSQL function "create_athlete" line 2 at SQL statement
STATEMENT: select * from athlete.create_athlete($1,$2,$3,$4,$5,$6,$7) as result
The stored procedure actually has 6 parameters (and should receive values $2 through $7 above) - the 7th comes from registering the return value as an out parameter. This has me confused - is it correct that it appears as 7 parameters when I register an out parameter for the return value?
From all the docs I've read I'm under the impression that the return value has to be registered as the first parameter:
registerQuery = "{? = call athlete.create_athlete(?,?,?,?,?,?)}";
...
CallableStatement cs = conn.prepareCall(registerQuery);
cs.registerOutParameter(1, Types.BOOLEAN);
cs.setString(2, email);
...
The error above suggests to me that there's a mismatch between stored procedure parameters and the parameters supplied to the insert statement. I've been following documentation for all of this but am clearly doing something wrong. How do I supply the proper parameters to the stored procedure and retrieve the return value after the call?
Depends on signature of your stored procedure type (function/procedure).
For function like one below, out parameter will be first one and will have param1 and param2 as second and third parameters.
DB Procedure (for function):
CREATE FUNCTION my_func (
param1 INT,
param2 INT)
RETURNS INT
AS
:
:
Java code (for function):
registerQuery = "{? = call my_func(?,?)}";
...
CallableStatement cs = conn.prepareCall(registerQuery);
cs.registerOutParameter(1, Types.INTEGER);
cs.setInteger(2, 10);
cs.setInteger(3, 10);
...
.
However for procedure like one below, out parameter will be third one and will have param1 and param2 as first and second parameters.
DB Procedure (for procedure):
CREATE PROCEDURE my_proc (
param1 INT,
param2 INT,
OUT param3 INT)
BEGIN
:
:
END;
Java code (for procedure):
registerQuery = "{call my_func(?,?,?)}";
...
CallableStatement cs = conn.prepareCall(registerQuery);
cs.registerOutParameter(3, Types.INTEGER);
cs.setInteger(1, 10);
cs.setInteger(2, 10);
...
.
Note that you can have multiple out parameters while only one return value.
Postgresql server supports named parameters but the jdbc driver does not support it(well not yet to my knowledge), so until such time only positional parameters is supported.
It turns out the issue was that the order of parameters passed to the stored procedure did not match the order those parameters were passed to the insert statement. I don't understand why PostgreSQL would use named parameters if order is significant.
For example, the signature of the stored procedure was as follows:
CREATE FUNCTION insert_Person (IN in_name TEXT, IN in_gender CHAR(1), IN in_bdate DATE) RETURNS BOOLEAN...
The INSERT statement contained within that stored procedure was as follows:
INSERT INTO Person (name, bdate, gender) VALUES (in_name, in_bdate, in_gender);
Changing the order of the parameters such that they matched in either the stored procedure signature or insert statement (I went with the former) resolved the issue.
Due to a restriction in the OCI layer, the JDBC drivers do not support the
passing of BOOLEAN parameters to PL/SQL stored procedures. If a PL/SQL
procedure contains BOOLEAN values, you can work around the restriction by
wrapping the PL/SQL procedure with a second PL/SQL procedure that accepts
the argument as an INT and passes it to the first stored procedure. When
the second procedure is called, the server performs the conversion from
INT to BOOLEAN.