Postgres的一些复杂功能使用了不属于SQL标准的运算符。一个简单的例子是POSIX正则表达式运算符的集合;我需要它们包含一个利用单词边界的where子句表达式。
假设我想找到大小为1的小部件,其中size是一个包含json编码的整数列表的字符串。
样本数据:
ID Size
1 "[1]"
2 "[1,2,4,12]"
3 "[4,12]"
4 "[2,4]"
这对于原始SQL来说是微不足道的:
SELECT * FROM widgets WHERE size ~ 'm1M'
但与科尔马相处会变得非常困难。Korma确实允许在where映射中使用谓词,但其功能非常有限。一些不起作用的东西:
=> (select "widgets" (where {:size ["~" "\m1\M"]}))
ClassCastException java.lang.String cannot be cast to clojure.lang.IFn korma.sql.engine/pred-vec (engine.clj:218)
=> (select "widgets" (where {:size [(raw "~") "\m1\M"]}))
Failure to execute query with SQL:
SELECT "widgets".* FROM "widgets" WHERE (?) :: [m1M]
=> (select "widgets" (where {:size (raw "~ '\m1\M'")}))
Failure to execute query with SQL:
SELECT "widgets".* FROM "widgets" WHERE ("widgets"."size" = ~ 'm1M') :: []
=> (sql-only (select "widgets" (where {:size [(raw "~ '\m1\M'")]})))
"SELECT "widgets".* FROM "widgets" WHERE (NULL)"
一个复杂的因素是,在这个条件之后,其他条件会动态添加到where映射中。因此,尽管以下示例有效,但它不允许构建该地图:
=> (sql-only (select "widgets" (where (raw "size ~ '\m1\M'"))))
"SELECT "widgets".* FROM "widgets" WHERE size ~ '\m1\M'"
那么,在korma中使用像~
这样的非标准运算符与where映射一起执行这种匹配可能吗?你会怎么做?最佳替代方案还是变通方案?
您可以从官方文档中添加额外的where
子句(http://sqlkorma.com/docs#select):
;; Multiple where's are joined with AND, so this
;; is also the same:
(-> (select* users)
(where {:first "john"})
(where {:last "doe"})
(as-sql))
所以你可以这样做:
(sql-only (select "widgets"
(where (raw "size ~ '\m1\M'"))
(where {:.. "?"})))
编辑:另一个选项
您可以创建自己的自定义谓词:
(require '[korma.sql.engine :refer [infix]])
(defn tilde
[k v]
(infix k "~" v))
(sql-only
(select "widgets"
(where {:size [tilde "\m1\M"]
:... [like "..."]})))