使用 array_position() 函式從 pg_stats 獲取列的最頻繁值
我正在嘗試執行這個簡單的查詢,以檢查某個值(1000)是否屬於 Postgres 查詢優化器使用的 MCV 列表:
SELECT array_position(most_common_vals, 1000) FROM pg_stats WHERE tablename = 'tenk1' AND attname = 'unique1';
但收到以下錯誤消息:
ERROR: function array_position(anyarray, integer) does not exist
如何修復?
array_position()
是此處描述的標準函式,以下語句按預期返回2 :SELECT array_position('{1,2,3}', 2);
解決方案
假設您的列的數據類型
tenk1.unique1
是integer
:SELECT array_position(most_common_vals::text::int[], 1000) FROM pg_stats WHERE tablename = 'tenk1' AND attname = 'unique1';
使用您的實際列類型和相應的數組類型。
您將獲得該位置,如果該值不在 MCV 列表中,則為 NULL。
解決方案很短 - 不像…
解釋
該函式
array_position()
被定義為採取(anyarray, anyelement)
(或(anyarray, anyelement, integer)
用於第二個變體)。該列
pg_stats.most_common_vals
具有多態數據類型**anyarray
**,能夠保存任何數據類型的數組 - 原因很明顯。
anyarray
並且anyelement
不允許作為使用者創建的表的數據類型。對於使用者來說,兩者都是多態偽類型。(但 Postgres 可以在系統表中使用它們。)同一函式中的多個多態變數必須解析為相同(或相應)的數據類型。手冊:
此外,如果聲明了位置
anyarray
和聲明了其他位置,則位置anyelement
中的實際數組類型anyarray
必須是其元素與出現在任何元素位置中的相同類型的數組。和:
因此,當使用多態類型聲明多個參數位置時,最終效果是只允許實際參數類型的某些組合。
大膽強調我的。
您發現了一個極端情況,即多態與第二個位置的- 或任何非多態類型的組合導致函式類型解析失敗。
anyarray``integer
1000
在您的表達式array_position(most_common_vals, 1000)
中是一個解析為integer
. 這些將以類似的方式失敗:array_position(most_common_vals, '1000') -- untyped string literal
ERROR: function array_position(anyarray, unknown) does not exist
array_position(most_common_vals, '1000'::text)
ERROR: function array_position(anyarray, text) does not exist
此外,沒有為 定義強制轉換
anyarray
,它是使用者域中的偽類型:SELECT * FROM pg_cast WHERE castsource = 'anyarray'::regtype; -- nothing found
解決方法是將 to
text
作為踏腳石,因為任何類型都可以轉換為text
. 然後轉換為integer[]
,得到上面的解決方案。最後,我認為這是函式類型解析的一個缺點,可以解決(容易嗎?)。但是由於數據類型
anyarray
不應該像這樣在使用者領域開始使用,我懷疑任何開發人員都會花時間在它上面……