使用Postgres在HugSQL或YesQL中强制转换多个值

时间:2018-07-26 19:10:08

标签: postgresql casting hugsql

我正在尝试将IP地址列表转换为::inet,但仅转换列表中的最后一个元素。

我尝试了以下操作,但似乎无济于事。

select * from ip_addresses where address in (:addresses::inet)

select * from ip_addresses where address in (:addresses)::inet

select * from ip_addresses where address in CAST (:addresses AS inet)

我不能简单地强制转换address::text,因为如果输入地址未指定子网,则匹配可能会失败。

2 个答案:

答案 0 :(得分:1)

类似HugSQL之类的声音正在用逗号分隔列表替换:addresses,因此您的(:addresses::inet)最终看起来像(addr, addr, addr, ..., addr::inet)。如果是这种情况,则可以将in (list)替换为= any(array),使用array constructor syntax,然后对整个数组进行强制转换:

select * from ip_addresses where address = any(array[:addresses]::inet[])

答案 1 :(得分:1)

我认为@ mu-is-too-short的答案是更好的解决方法-使用Postgresql的功能来解决问题。

即使如此,如果您不想为此使用Postgresql数组,也可以使用Clojure Expression来为HugSQL中的向量中的每个值生成一个强制转换:

-- :name x 
-- :require [clojure.string :as string]
select * from test where id in (
/*~
(clojure.string/join 
  ","
  (map-indexed (fn [i v] (str ":values." i "::int")) (:values params)))
~*/
)

最终会给你这样的东西

(x-sqlvec {:values ["1" "2"]})
;=> ["select * from test where id in (?::int,?::int)" "1" "2"]

因此,上面的方法使用值向量,并使用HugSQL's deep-get syntax分别提取每个值,并将类型转换添加到每个值。因此,您正在有效地动态构建一组新的HugSQL参数,如下所示:

in (:values.0::int, :values.1::int, :values.2::int)