Postgresql JDBC表值参数

13

MSSQL有一个很棒的功能叫做表值参数。它允许您将自定义数据表传递给存储过程和函数。

我想知道在使用JDBC时,如果有的话,在PostgreSQL中是否存在相应的功能? 我知道可以将数组作为函数参数传递,但似乎仅限于PostgreSQL数据类型。

考虑以下PL/pgSQL代码:

CREATE  TYPE number_with_time AS(
_num   float,
_date  timestamp
);

并且这个函数头:

CREATE OR REPLACE FUNCTION myfunc(arr number_with_time[])

有人可以发布一个使用JDBC驱动程序调用带有用户定义数据类型数组的函数的Java代码吗?


1
我认为没有直接的等价物,但您可以使用全局临时表来替代它。 - user330315
你能提供一些相关代码示例吗? - Orr
复合类型的数组也是一个不错的选择,您可以像使用结果集一样在函数中处理它,例如 SELECT * FROM unnest(arr)(尽管这可能不是最节省内存的方式)。 - pozs
如果您选择使用数组,您可以在 SQL 中使用以下代码进行调用:ARRAY[(1, 'now'), (2, 'now')]::number_with_time[] - 或者从结果集中创建一个数组,使用 array_agg(("float_val", "timestamp_val")::number_with_time) - pozs
pozs - 我不确定这回答了我的问题。因为我的问题是如何使用JDBC驱动程序将此数组作为参数传递,您能否提供与您的评论相匹配的JAVA代码? - Orr
@Orr 使用预处理语句吗?只需在查询中使用 "... ARRAY[(?, ?), (?, ?)]::number_with_time[] ..." 即可。http://docs.oracle.com/javase/tutorial/jdbc/basics/prepared.html - pozs
3个回答

6
假设您想从客户端传递值。如果这些值已经存在于数据库中,那么有其他更简单的方法。 array of composite_type 的语法
我知道可以将数组作为函数参数进行传递,但似乎仅限于 PostgreSQL 数据类型。
您可以传递的内容似乎受到 Java Types and JDBC Types 的限制,并且似乎没有为数组类型提供规定,更不用说复合值的数组了…
然而,您总是可以传递 text 表示。我基于两个基本事实进行构建:
引用 手册:
任何内置或用户定义的基本类型、枚举类型或复合类型的数组均可创建。尚不支持域的数组。
加粗部分是我强调的。因此,在你创建了在问题中定义的类型number_with_time,或者定义了一个具有相同列的表格,该表格会自动在系统中注册行类型后,你还可以使用数组类型number_with_time[]
2. 对于每个值都有text表示。
因此,number_with_time[]也有文本表示形式:
'{"(1,2014-04-20 20:00:00)","(2,2014-04-21 21:00:00)"}'::number_with_time[]

函数调用

实际的函数调用取决于您在函数中定义的返回值 - 这在您的问题中是隐藏的。

为了避免JDBC中的数组处理引起的复杂性,请传递text表示。创建一个带有text参数的函数。

我不会将名称“date”用于timestamp。使用这个稍微调整过的类型定义进行操作:

CREATE TYPE number_with_time AS(
   _num float
 , _ts  timestamp
);

简单的SQL函数:
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$;

呼叫:

SELECT myfunc_sql('{"(1,2014-04-20 20:00:00)","(2,2014-04-21 21:00:00)"}');

db<>fiddle 这里
旧版 sqlfiddle

演示:

  • 上述 SQL 函数
  • PL/pgSQL 变体
  • 有关复合类型数组的一些语法变体
  • 函数调用

像调用其他简单 text 参数函数一样调用该函数:

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(); 

在Postgres JDBC手册中了解详情。

通过JDBC返回整个表的示例:


1
尝试像这样做些事情:

                ------------------ your connection
                V
Array inArray = conn.createArrayOf("integer", new Integer[][] {{1,10},{2,20}});
stmt.setArray(1, inArray);

一个你可以用来构建测试的示例方法:

    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();
    }

有用的链接:


0
你的问题是PostgreSQL可以将表或复杂类型作为函数的参数,还是可以将"表或复杂类型"的数组作为函数的参数? PostgreSQL支持所有这些。当你创建一个表时,它会自动创建一个与表名相同的复杂类型。 例如:
digoal=# create table tbl123(id int, info text);
CREATE TABLE
digoal=# select typname from pg_type  where typname='tbl123';
 typname 
---------
 tbl123
(1 row)

你可以直接在函数中使用这种类型。 例如:

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)

数组也可以在PostgreSQL函数中使用。 如果您不知道如何在Java中构建数组,我认为这个示例可以帮助您。

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)

我的目标是获得一个JAVA示例,用于将自定义数据类型的数组传递给PL/pgSQL函数,我不认为这有帮助。 - Orr
@Orr - 你成功地将自定义Java对象数组传递给PostgreSQL函数了吗?如果是的话,你是怎么做到的? - robert
@robert - 实际上,这里没有任何答案解决了它,但我刚刚找到了一个临时的解决办法。不确定是否有简单的解决方案。 - Orr
在回答问题之前,请仔细阅读问题,我不明白这如何有助于从Java传递类型到pg。 - downvoteit

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接