亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

Postgres:使用 NULLIF 時獲取“...超出整數類型的范圍”

Postgres:使用 NULLIF 時獲取“...超出整數類型的范圍”

Go
胡說叔叔 2022-10-24 15:04:45
對于上下文,這個問題發生在我使用默認 postgres 數據庫驅動程序編寫的 Go 程序中。我一直在構建一個服務來與一個 postgres 數據庫對話,該數據庫有一個類似于下面列出的表: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 ($1, $2)ON CONFLICT name DO UPDATE SET    some_other_id = COALESCE(NULLIF($2, 0), object.some_other_id)我還有一個帶有如下基礎查詢的“更新”端點:UPDATE objectSET some_other_id = COALESCE(NULLIF($2, 0), object.some_other_id)WHERE name = $1問題:每當我運行更新查詢時,我總是遇到錯誤,引用字段“some_other_id”:pq:值“1010101010144”超出整數類型的范圍但是,即使該行已經存在于數據庫中(當它必須評估 COALESCE 語句時),此錯誤也不會發生在查詢的“upsert”版本上。通過將 COALESCE 語句更新為如下所示,我已經能夠防止此錯誤:COALESCE(NULLIF($2, 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($2, 0), object.some_other_id) WHERE name = $1`,    "a name",    1010101010144,)兩個查詢都以完全相同的方式執行。編輯:還在我當前的解決方法中更正了參數(從$51到$2)。我還想借此機會指出,該查詢確實適用于我提出的修復,這表明問題在于我將 postgres 與NULLIF語句中的類型混淆了?在我的代碼和數據庫之間沒有存儲過程要求一個INTEGERarg,至少我已經寫過。
查看完整描述

2 回答

?
莫回無

TA貢獻1865條經驗 獲得超7個贊

這與 postgres 解析器如何解析參數類型有關。我不知道它是如何實現的,但考慮到觀察到的行為,我會假設INSERT查詢不會失敗,因為很明顯(name,some_other_id) VALUES ($1,$2)參數應該與目標列$2具有相同的類型,即 type 。然后,此類型信息也用于查詢部分的表達式。some_other_idint8NULLIFDO UPDATE SET

您還可以通過使用(name) VALUES ($1)in來測試此假設INSERT,您將看到 in 中的NULLIF表達式隨后將以與查詢DO UPDATE SET中相同的方式失敗。UPDATE

因此UPDATE查詢失敗,因為沒有足夠的上下文供解析器推斷$2參數的準確類型。解析器可以用來推斷類型的“最接近”的東西$2NULLIF調用表達式,特別是它使用調用表達式的第二個參數的類型,即0類型為int4,然后它使用該類型信息第一個論點,即$2。

為避免此問題,您應該對無法準確推斷類型的任何參數使用顯式類型轉換。即使用NULLIF($2::int8, 0).


查看完整回答
反對 回復 2022-10-24
?
心有法竹

TA貢獻1866條經驗 獲得超5個贊

COALESCE(NULLIF($51, CAST(0 AS BIGINT)), object.some_other_id)

五十一?真的嗎?

pq:值“1010101010144”超出整數類型的范圍

請注意,錯誤消息中的數據類型是integer,而不是bigint。

我認為錯誤的原因是顯示代碼不足。于是我拿出一個魔法水晶球,用手傳球。

一個“安裝”端點,它像這樣有效地充當一個 upsert 函數

我還有一個“更新”端點

您是否將端點稱為PostgreSQL 函數(存儲過程)?我想是的。另外 $1, $2 看起來像 PostgreSQL 函數參數。

魔法水晶球說:您有兩個具有不同數據類型參數的 PostgreSQL 函數:

  1. “安裝”端點具有 $2 函數參數作為bigint數據類型。看起來像CREATE FUNCTION Install(VARCHAR(255), bigint)

  2. “更新”端點具有 $2 函數參數作為整數數據類型,而不是bigint。它看起來像CREATE FUNCTION Update(VARCHAR(255), integer)。

最后,我會更容易理解地重寫你的條件:

UPDATE object

SET some_other_id = 

CASE 

WHEN $2 = 0 THEN object.some_other_id

ELSE $2

END

WHERE name = $1


查看完整回答
反對 回復 2022-10-24
  • 2 回答
  • 0 關注
  • 181 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號