Postgres:使用 NULLIF 时出现“...超出整数类型的范围”
Postgres: getting "... is out of range for type integer" when using NULLIF
对于上下文,这个问题发生在我使用默认的 postgres 数据库驱动程序编写的 Go 程序中。
我一直在构建与 postgres 数据库对话的服务,该数据库具有 table 类似于下面列出的数据库:
CREATE TABLE object (
id SERIAL PRIMARY KEY NOT NULL,
name VARCHAR(255) UNIQUE,
some_other_id BIGINT UNIQUE
...
);
我已经为这个项目创建了一些端点,包括一个“安装”端点,它有效地充当一个 upsert 函数,如下所示:
INSERT INTO object (name, some_other_id)
VALUES (, )
ON CONFLICT name DO UPDATE SET
some_other_id = COALESCE(NULLIF(, 0), object.some_other_id)
我还有一个“更新”端点,其底层查询如下:
UPDATE object
SET some_other_id = COALESCE(NULLIF(, 0), object.some_other_id)
WHERE name =
问题:
每当我 运行 更新查询时,我总是 运行 进入错误,引用字段 "some_other_id":
pq: value "1010101010144" is out of range for type integer
然而,这个错误永远不会发生在查询的“upsert”版本上,即使该行已经存在于数据库中(当它必须计算 COALESCE 语句时)。我已经能够通过将 COALESCE 语句更新为如下所示来防止此错误:
COALESCE(NULLIF(, CAST(0 AS BIGINT)), object.some_other_id)
但由于第一次查询时从未发生过这种情况,我想知道这种不一致是因为我做错了什么还是我不明白?还有这方面的最佳做法是什么,我应该投射所有价值吗?
我肯定将 64 位整数传递给“some_other_id”的查询,即使没有显式类型转换,第一个查询也适用于 Go 实现。
如果需要更多信息(或 Go 实现),请告诉我,非常感谢! (:
编辑:
为了消除混淆,查询直接在 Go 代码中执行,如下所示:
res, err := s.db.ExecContext(ctx, `UPDATE object SET some_other_id = COALESCE(NULLIF(, 0), object.some_other_id) WHERE name = `,
"a name",
1010101010144,
)
两个查询的执行方式完全相同。
编辑: 还更正了我当前解决方法中的参数(从 </code> 到 <code>
)。
我还想借此机会指出,查询确实适用于我建议的修复,这表明问题出在我混淆了 postgres 和 NULLIF
语句中的类型?在我的代码和数据库之间没有要求 INTEGER
arg 的存储过程,至少我已经写过了。
COALESCE(NULLIF(, CAST(0 AS BIGINT)), object.some_other_id)
五十一?真的吗?
pq: value "1010101010144" is out of range for type integer
注意,报错信息中的数据类型是integer,不是bigint.
我认为错误的原因是显示的代码。 于是我拿出一个神奇的crystal球,用手一传。
an "Install" endpoint which effectively acts as an upsert function like so
I also have an "Update" endpoint
您将端点称为 PostgreSQL function(存储过程)吗?我想是的。
另外 $1, $2 看起来像 PostgreSQL 函数参数。
神奇的 crystal 球说:你有两个具有不同数据类型参数的 PostgreSQL 函数:
“安装”端点有 $2 函数参数作为 bigint 数据类型。看起来像 CREATE FUNCTION Install(VARCHAR(255), bigint)
“更新”端点有 $2 函数参数作为 整数 数据类型,而不是 bigint。看起来像 CREATE FUNCTION Update(VARCHAR(255), integer)
.
最后,我会重写你的条件更容易理解:
UPDATE object
SET some_other_id =
CASE
WHEN = 0 THEN object.some_other_id
ELSE
END
WHERE name =
这与 postgres 解析器如何解析参数类型有关。我不知道它究竟是如何实现的,但考虑到观察到的行为,我会假设 INSERT
查询不会失败,因为从 (name,some_other_id) VALUES (,)
可以清楚地看出 </code> 参数应该与目标 <code>some_other_id
列具有相同类型,其类型为 int8
。此类型信息随后也用于查询 DO UPDATE SET
部分的 NULLIF
表达式。
您还可以通过在 INSERT
中使用 (name) VALUES ()
来测试这个假设,您会看到 DO UPDATE SET
中的 NULLIF
表达式将以同样的方式失败正如在 UPDATE
查询中所做的那样。
所以 UPDATE
查询失败,因为解析器没有足够的上下文来推断 </code> 参数的准确类型。解析器可以用来推断 <code>
类型的“最接近”的东西是 NULLIF
调用表达式,特别是它使用调用表达式的第二个参数的类型,即 0
,其类型为 int4
,然后它使用该类型信息作为第一个参数,即 </code>.</p>
<p>为避免此问题,您应该对无法准确推断类型的任何参数使用显式类型转换。即使用 <code>NULLIF(::int8, 0)
.
对于上下文,这个问题发生在我使用默认的 postgres 数据库驱动程序编写的 Go 程序中。
我一直在构建与 postgres 数据库对话的服务,该数据库具有 table 类似于下面列出的数据库:
CREATE TABLE object (
id SERIAL PRIMARY KEY NOT NULL,
name VARCHAR(255) UNIQUE,
some_other_id BIGINT UNIQUE
...
);
我已经为这个项目创建了一些端点,包括一个“安装”端点,它有效地充当一个 upsert 函数,如下所示:
INSERT INTO object (name, some_other_id)
VALUES (, )
ON CONFLICT name DO UPDATE SET
some_other_id = COALESCE(NULLIF(, 0), object.some_other_id)
我还有一个“更新”端点,其底层查询如下:
UPDATE object
SET some_other_id = COALESCE(NULLIF(, 0), object.some_other_id)
WHERE name =
问题:
每当我 运行 更新查询时,我总是 运行 进入错误,引用字段 "some_other_id":
pq: value "1010101010144" is out of range for type integer
然而,这个错误永远不会发生在查询的“upsert”版本上,即使该行已经存在于数据库中(当它必须计算 COALESCE 语句时)。我已经能够通过将 COALESCE 语句更新为如下所示来防止此错误:
COALESCE(NULLIF(, CAST(0 AS BIGINT)), object.some_other_id)
但由于第一次查询时从未发生过这种情况,我想知道这种不一致是因为我做错了什么还是我不明白?还有这方面的最佳做法是什么,我应该投射所有价值吗?
我肯定将 64 位整数传递给“some_other_id”的查询,即使没有显式类型转换,第一个查询也适用于 Go 实现。
如果需要更多信息(或 Go 实现),请告诉我,非常感谢! (:
编辑:
为了消除混淆,查询直接在 Go 代码中执行,如下所示:
res, err := s.db.ExecContext(ctx, `UPDATE object SET some_other_id = COALESCE(NULLIF(, 0), object.some_other_id) WHERE name = `,
"a name",
1010101010144,
)
两个查询的执行方式完全相同。
编辑: 还更正了我当前解决方法中的参数(从 </code> 到 <code>
)。
我还想借此机会指出,查询确实适用于我建议的修复,这表明问题出在我混淆了 postgres 和 NULLIF
语句中的类型?在我的代码和数据库之间没有要求 INTEGER
arg 的存储过程,至少我已经写过了。
COALESCE(NULLIF(, CAST(0 AS BIGINT)), object.some_other_id)
五十一?真的吗?
pq: value "1010101010144" is out of range for type integer
注意,报错信息中的数据类型是integer,不是bigint.
我认为错误的原因是显示的代码。 于是我拿出一个神奇的crystal球,用手一传。
an "Install" endpoint which effectively acts as an upsert function like so
I also have an "Update" endpoint
您将端点称为 PostgreSQL function(存储过程)吗?我想是的。 另外 $1, $2 看起来像 PostgreSQL 函数参数。
神奇的 crystal 球说:你有两个具有不同数据类型参数的 PostgreSQL 函数:
“安装”端点有 $2 函数参数作为 bigint 数据类型。看起来像
CREATE FUNCTION Install(VARCHAR(255), bigint)
“更新”端点有 $2 函数参数作为 整数 数据类型,而不是 bigint。看起来像
CREATE FUNCTION Update(VARCHAR(255), integer)
.
最后,我会重写你的条件更容易理解:
UPDATE object
SET some_other_id =
CASE
WHEN = 0 THEN object.some_other_id
ELSE
END
WHERE name =
这与 postgres 解析器如何解析参数类型有关。我不知道它究竟是如何实现的,但考虑到观察到的行为,我会假设 INSERT
查询不会失败,因为从 (name,some_other_id) VALUES (,)
可以清楚地看出 </code> 参数应该与目标 <code>some_other_id
列具有相同类型,其类型为 int8
。此类型信息随后也用于查询 DO UPDATE SET
部分的 NULLIF
表达式。
您还可以通过在 INSERT
中使用 (name) VALUES ()
来测试这个假设,您会看到 DO UPDATE SET
中的 NULLIF
表达式将以同样的方式失败正如在 UPDATE
查询中所做的那样。
所以 UPDATE
查询失败,因为解析器没有足够的上下文来推断 </code> 参数的准确类型。解析器可以用来推断 <code>
类型的“最接近”的东西是 NULLIF
调用表达式,特别是它使用调用表达式的第二个参数的类型,即 0
,其类型为 int4
,然后它使用该类型信息作为第一个参数,即 </code>.</p>
<p>为避免此问题,您应该对无法准确推断类型的任何参数使用显式类型转换。即使用 <code>NULLIF(::int8, 0)
.