在 Java 中,调用 PostgreSQL 函数,为什么我收到错误消息,提示该函数不存在?

发布于 2024-12-02 09:48:30 字数 1015 浏览 0 评论 0原文

我在数据库中有这个过程:

CREATE OR REPLACE FUNCTION replacePageRelevance(id INT, value REAL) RETURNS VOID AS $$
BEGIN
INSERT INTO pageRelevance VALUES (id,value);
EXCEPTION WHEN unique_violation THEN
    UPDATE pageRelevance SET relevance = value WHERE pageId = id;       
END
$$
LANGUAGE plpgsql;

并且此代码调用此函数:

try (CallableStatement cstm = conn.prepareCall(PAGE_RELEVANCE_SQL)) {
        for (Map.Entry<Integer, Double> entry : weightMap.entrySet()) {
            cstm.setInt(1, entry.getKey());
            cstm.setDouble(2, entry.getValue());
            cstm.addBatch();
        }
        cstm.executeBatch();
    } catch (SQLException e) {
        LOGGER.error("Error discovering pages relevance: " + e.getNextException());
    }
}

这不起作用,我收到一条错误消息,通知函数replacepagerelevance(整数,双精度)不存在。。为什么?

生成的调用如下:SELECT ReplacePageRelevance('882','8.0')。如果我在 pgAdmin 中执行它,它可以工作,但不能从 Java 中执行。

I have this procedure in the database:

CREATE OR REPLACE FUNCTION replacePageRelevance(id INT, value REAL) RETURNS VOID AS $
BEGIN
INSERT INTO pageRelevance VALUES (id,value);
EXCEPTION WHEN unique_violation THEN
    UPDATE pageRelevance SET relevance = value WHERE pageId = id;       
END
$
LANGUAGE plpgsql;

And this code that calls this function:

try (CallableStatement cstm = conn.prepareCall(PAGE_RELEVANCE_SQL)) {
        for (Map.Entry<Integer, Double> entry : weightMap.entrySet()) {
            cstm.setInt(1, entry.getKey());
            cstm.setDouble(2, entry.getValue());
            cstm.addBatch();
        }
        cstm.executeBatch();
    } catch (SQLException e) {
        LOGGER.error("Error discovering pages relevance: " + e.getNextException());
    }
}

This is not working, I'm getting an error informing that function replacepagerelevance(integer, double precision) doesn't exists.. Why?

The generated call is this: SELECT replacePageRelevance('882','8.0'). If I execute this in pgAdmin, it works, but not from Java.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

韶华倾负 2024-12-09 09:48:30

这是因为您的 PL/pgSQL 函数定义为:

replacePageRelevance(id INT, value REAL)

REAL 是单精度浮点,但在 Java 方面,您尝试将其用作双精度,并且对于这种情况没有隐式转换。

您应该使用 CallableStatement.setFloat 用于单精度 REAL 数据类型,但它并不明确,因为阅读 Java API:

将指定参数设置为给定的 Java 浮点值。这
驱动程序将其发送到 SQL FLOAT 值时将其转换为
数据库。

由于 FLOAT 是 Postgres 中 DOUBLE PRECISION同义词,因此它的运行效果与 CallableStatement.setDouble 产生错误消息(这很奇怪)。

当然,您可以将函数更改为 replacePageRelevance(id INT, value DOUBLE PRECISION),正如我检查的那样,它与您的代码配合得很好。

不过,如果您想在函数中保留 REAL ),请使用显式强制转换,如下所示:

String PAGE_RELEVANCE_SQL = "{call replacePageRelevance(?, ?::real)}";

It's because your PL/pgSQL function is defined as:

replacePageRelevance(id INT, value REAL)

REAL is a single precision floating point, but on Java side you're trying to use it as double precision and there is no implicit casting for such situation.

You should rather use CallableStatement.setFloat for single precision REAL datatype, however it's not co clear, becuase reading Java API:

Sets the designated parameter to the given Java float value. The
driver converts this to an SQL FLOAT value when it sends it to the
database.

Since FLOAT is a synonym for DOUBLE PRECISION in Postgres it runs with same effect as CallableStatement.setDouble producing error message (that's weird).

Of course you could just change your function to replacePageRelevance(id INT, value DOUBLE PRECISION) and as I checked it works well with your code.

Nevertheless, If you want to keep REAL in your function), then use explicit cast like this:

String PAGE_RELEVANCE_SQL = "{call replacePageRelevance(?, ?::real)}";
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文