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

Casting Multiple Values in HugSQL or YesQL with Postgres

我正在尝试将 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,因为如果输入地址没有指定子网,匹配可能会失败。

听起来 HugSQL 正在用逗号分隔列表替换 :addresses,因此您的 (:addresses::inet) 最终看起来像 (addr, addr, addr, ..., addr::inet)。如果是这种情况,那么您可以将 in (list) 替换为 = any(array), use the array constructor syntax,并将强制转换应用于整个数组:

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

我认为 @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)