【问题标题】:Return rows from a PL/pgSQL function从 PL/pgSQL 函数返回行
【发布时间】:2012-08-05 11:16:21
【问题描述】:

我在 PostgreSQL 中有一个程序:

CREATE OR REPLACE FUNCTION get_geom_difference()
RETURNS void AS
$$
BEGIN
SELECT filedata.num,st_area(ST_Difference(ST_TRANSFORM(filedata.the_geom,70066),filedata_temp.the_geom))
FROM filedata, filedata_temp
Where filedata.num=filedata_temp.num

end;
$$
LANGUAGE 'plpgsql'

我用 Java 调用它并希望得到这个过程的结果。如何更改此程序以使其有可能获得结果?以及如何在 JDBC 中使用它?

现在我用这个:

Integer fileId;
Class.forName("org.postgresql.Driver");
Connection connect= null;
connect = DriverManager.getConnection("jdbc:postgresql://localhost:5432/postgis","postgres","123456");
java.sql.CallableStatement proc =  connect.prepareCall("{?=call get_geom_difference()}");
proc.registerOutParameter(1, java.sql.Types.Integer);
proc.execute();
ResultSet results = (ResultSet) proc.getObject(1);
while (results.next()) {
fileId=r.getInt("num");
}
proc.close();
connect.close();
out.println(fileId);

但是当我尝试在 JDBC 中调用该过程时,我得到了

error org.apache.jasper.JasperException: 发生异常 在第 25 行处理 JSP 页面 /commit_changes.jsp

第 25 行是:proc.execute();

【问题讨论】:

    标签: java postgresql jdbc plpgsql


    【解决方案1】:

    正确的函数定义

    CREATE OR REPLACE FUNCTION get_geom_difference()
      RETURNS TABLE (num mumeric, my_area geometry) AS
    $BODY$
       SELECT f.num
             ,st_area(ST_Difference(ST_TRANSFORM(f.the_geom, 70066), t.the_geom))
       FROM   filedata f
       JOIN   filedata_temp t USING (num);
    $BODY$
    LANGUAGE sql;

    您正在返回一个复合类型(两列)的 SET,您必须相应地声明该函数。 RETURNS TABLE 是最方便的方式。

    请务必对查询中的列名进行表限定,以免它们与OUT 同名列冲突。

    您可以使用language SQL function 进行此基本查询(或者您可以只执行原始 SQL),不需要 plpgsql。

    在SQL中调用函数

    SELECT * FROM get_geom_difference();
    

    通过 JDBC 实现

    我引用手册here

    不应通过 CallableStatement 接口,但应该使用普通的 语句或 PreparedStatement 接口。

    我也从网站上拿了这个例子并对其进行了改编:

    Statement stmt = conn.createStatement();
    stmt.execute(" <function definition from above goes here> ");
    ResultSet rs = stmt.executeQuery("SELECT * FROM get_geom_difference();");
    while (rs.next()) {
        // do something
    }
    rs.close();
    stmt.close();
    

    您也可以使用引用器。阅读more in the manual

    【讨论】:

    • 嘿,太好了!不知何故,我错过了RETURNS TABLE 选项,并且一直在定义记录类型并返回SETOF 那些。你的方法更好。 :-)
    • @kgrittn:随 v8.4 引入。我不想再没有它了,这让使用表函数变得更加容易。
    • 感谢您的回答。但是你能告诉我如何在 jdbc 中正确使用这个函数吗?
    • @KliverMax:我添加了更多解释和链接以使其清晰。
    • 请看这个问题的最后更新stackoverflow.com/questions/11859723/…
    【解决方案2】:

    在您的定义中,您的函数不返回任何内容RETURNS void。 如果您想要 num 数据类型,只需更改为 RETURNS numeric。此外,要使其正常工作,请对某个数字变量 SELECT INTO var 执行选择并将 return var 添加到函数末尾。

    【讨论】:

    • begin之前添加declare tt numeric
    • 感谢您的工作。但是当我尝试在 jdbc 中调用过程时,我得到 error org.apache.jasper.JasperException: An exception occurred processing JSP page /commit_changes.jsp at line 25 第 25 行是 `proc.execute();
    • 在 java 中实际执行 SP 执行给你的信息是什么错误
    • 此答案适用于返回 one 数值的函数,而手头的函数并非如此。
    【解决方案3】:

    虽然 Erwin 提供了一个很好的答案,但我想我会分享一个函数接受参数的版本,并且我在函数体中使用了新的 postgres 返回查询语法。不同之处在于它似乎设置参数你必须使用 PreparedStatement 接口而不是更高级别的 Statement。 这是我的 pg 函数

    CREATE OR REPLACE FUNCTION gettools(_userid bigint)
      RETURNS table(id bigint,itemname character varying(250)) AS
    $BODY$
    
    begin   
        return query 
        select distinct a.id, a.itemname 
        from tool a inner join tooltie b
         on a.id = b.toolid 
         and b.userid=_userid;
    end;
    $BODY$
      LANGUAGE plpgsql STABLE
      COST 100;
    

    这是我的java,它只是用数据填充地图

      private static final String GET_DATASOURCES = "select * from getdatasources(?)";
    
        public Map<Long, String> getAuthDataSources(Long userid) {
            Map<Long, String> auths = new TreeMap<>();
            try {
              if (connection == null || connection.isClosed()) {
                init();
              }
              PreparedStatement cs = connection.prepareStatement(GET_DATASOURCES);
              // this is where to set the param ? for the function
              cs.setLong(1, userid);
              connection.setAutoCommit(false);        
              ResultSet result = cs.executeQuery();
    
              while (result.next()) {
                Long id = result.getLong(1);
                String itemname = result.getString(2);
                auths.put(id, itemname);
              }
              cs.close();
              connection.commit();
              connection.setAutoCommit(true);
              connection.close();
            } catch (SQLException ex) {
              LOG.error("error getting data sources", ex);
    
            }
            return auths;
          }
    

    希望这对某人有所帮助。

    【讨论】:

    • 虽然LANGUAGE plpgsql 很好(并且在某些 情况下是一个不错的选择),但您实际上并不需要它。 LANGUAGE sql 可以完成这项工作,并且通常是简单功能的更好选择。 More here.
    猜你喜欢
    • 2013-06-19
    • 1970-01-01
    • 2012-08-16
    • 2012-08-10
    • 1970-01-01
    • 1970-01-01
    • 2017-08-24
    • 2022-01-19
    • 1970-01-01
    相关资源
    最近更新 更多