如何使 HoneySQL 处理顺序作为复合键?
Posted
技术标签:
【中文标题】如何使 HoneySQL 处理顺序作为复合键?【英文标题】:How can I make HoneySQL handle order by as a compound key? 【发布时间】:2016-10-30 22:01:43 【问题描述】:请注意,输出已被“风格化”,因此在 SO 上阅读效果更好。
我有什么...
(sql/format
(->
(sqlh/select :*)
(sqlh/from :event)
(sqlh/merge-where [:in :field_id ["1673576", "1945627", "1338971"]])
(sqlh/merge-where [:in :layer ["fha.abs" "fha.rank" "fha.true-color"]])
(sqlh/merge-order-by :field_id)
(sqlh/merge-order-by :layer)
(sqlh/merge-order-by :event_date)
(sqlh/limit 5)))
=>
["SELECT *
FROM event
WHERE ((field_id in (?, ?, ?)) AND (layer in (?, ?, ?)))
ORDER BY field_id, layer, event_date
LIMIT ?"
"1673576"
"1945627"
"1338971"
"fha.abs"
"fha.rank"
"fha.true-color"
5]
我想要什么...
(sql/format
(->
(sqlh/select :*)
(sqlh/from :event)
(sqlh/merge-where [:in :field_id ["1673576", "1945627", "1338971"]])
(sqlh/merge-where [:in :layer ["fha.abs" "fha.rank" "fha.true-color"]])
;;; this doesn't work, but is conceptually what I'm looking for
(sqlh/merge-order-by [:field_id :layer :event_date])
(sqlh/limit 5)))
=>
["SELECT *
FROM event
WHERE ((field_id in (?, ?, ?)) AND (layer in (?, ?, ?)))
ORDER BY (field_id, layer, event_date)
LIMIT ?"
"1673576"
"1945627"
"1338971"
"fha.abs"
"fha.rank"
"fha.true-color"
5]
如何让 HoneySQL 发出将我的 order by 子句视为表本身用作主键的复合键的 SQL?
似乎 HoneySQL 应该能够做到这一点,因为当在 where 子句中遇到相同的挑战时,它“做正确的事”......
(sql/format
(->
(sqlh/select :*)
(sqlh/from :event)
(sqlh/merge-where [:= [:field_id :layer :event_date] ["1338971" "fha.abs" (c/from-string "2011-08-02T10:54:55-07")]])))
=>
["SELECT * FROM event WHERE (field_id, layer, event_date) = (?, ?, ?)"
"1338971"
"fha.abs"
#object[org.joda.time.DateTime 0xe59f807 "2011-08-02T17:54:55.000Z"]]
【问题讨论】:
第二个生成的查询与第一个有什么不同? @AshishNegi 在第二个查询中,order by 子句位于一个元组而不是 3 个单独的字段上。最终,这将允许我在单个语句中反转排序顺序。 是的,但不是都给出相同的结果?...无论您有元组还是单个字段。 @AshishNegi 它给出了相同的初始结果,这是正确的,但是当我期待我想要做的事情时;实现一个只需要 LIMIT 而不是 OFFSET 的分页解决方案,我需要能够将这 3 个不同的字段视为一个单元。 HoneySQL 在 where 子句中对此做了正确的事情(我在问题中添加了这个),我正在寻找 order-by 中的等效行为。 也许你应该尝试提出关于限制/偏移的真正问题,以及他们如何在有/没有元组的情况下给出不同的结果.. 【参考方案1】:首先您需要查看order-by
上的格式行为
(sql/format :order-by [:c1 :c2])
=> ["ORDER BY c1, c2"]
(sql/format :order-by [[:c1 :desc] :c2])
=> ["ORDER BY c1 DESC, c2"]
这就是将要生成的关于order-by的结构。
如果您查看宏defhelper
,它将做两件事。
-
规范类型的defrecord
定义一个函数来调用多重方法
(do
(defmethod
build-clause
:order-by
[_ m fields]
(assoc m :order-by (collify fields)))
(defn order-by [& args__14903__auto__]
(let [[m__14904__auto__ args__14903__auto__] (if
(plain-map?
(first
args__14903__auto__))
[(first
args__14903__auto__)
(rest
args__14903__auto__)]
[
args__14903__auto__])]
(build-clause :order-by m__14904__auto__ args__14903__auto__)))
(alter-meta! #'order-by assoc :arglists '([fields] [m fields])))
collify
非常简单。
(defn collify [x]
(if (coll? x) x [x]))
所以,我们需要查看defn order-by
函数。
当您拨打(sqlh/merge-order-by [:a :b])
时,
args__14903__auto__ = '( [:a :b])
第一个if
将创建两个变量m__14904__auto__ =
和args__14903__auto__ = (rest args__14903__auto__) = ([:a :b])
。
所以,我猜merge-order-by函数是错误的。
我这样解决你的问题。
(sql/format
(->
(sqlh/select :*)
(sqlh/from :event)
(sqlh/merge-where [:in :field_id ["1673576", "1945627", "1338971"]])
(sqlh/merge-where [:in :layer ["fha.abs" "fha.rank" "fha.true-color"]])
(sqlh/merge-order-by [:field_id :desc] :layer :event_date)
(sqlh/limit 5)))
【讨论】:
不完全,但很努力。我越是盯着这个,我就越觉得 HoneySQL 助手无法做到这一点,但也许没关系。当我查看 PostgreSQL 对实际查询的解释时, ORDER BY (field_id, layer, event_date) DESC, vs (ORDER BY field_id DESC, layer DESC, event_date DESC);它似乎产生了相同的查询计划......它只是让我感到困扰,我必须这样做如此细粒度,因为帮助类并没有真正直接映射到底层 SQL【参考方案2】:已经 2 年多了,但我终于对 Clojure 有了足够的了解,并且与 HoneySQL 合作了足够长的时间来了解年轻时的自己所缺少的东西。它不希望复合键作为向量:sqlh/order-by
是可变的:
(doc sqlh/order-by)
-------------------------
honeysql.helpers/order-by
([& fields] [m & fields])
nil
它真正想要的是(sqlh/order-by :field_id :layer [:event_date :desc])
。该向量仅用于对特定字段排序 DESC。
所以这就是我想要做的:
(-> (sqlh/select :*)
(sqlh/from :event)
(sqlh/merge-where [:in :field_id field-ids])
(sqlh/merge-where (cond (not-empty layers) [:in :layer layers]))
(sqlh/merge-where (make-where-for-timestamp
:event_date event-date-from event-date-to))
(sqlh/merge-where (make-where-for-timestamp
:updated_at updated-at-from updated-at-to))
(sqlh/order-by :field_id :layer [:event_date :desc])
sql/format)
=>
["SELECT * FROM event WHERE ((field_id in (?)) AND (layer in (?, ?, ?))) ORDER BY field_id, layer, event_date DESC"
"1325629"
"fha.true-color"
"fha.abs"
"fha.rank"]
@savior 在https://***.com/a/40356529/688355 一直都是正确的。我的 Clojure 不够好,无法理解它。
【讨论】:
以上是关于如何使 HoneySQL 处理顺序作为复合键?的主要内容,如果未能解决你的问题,请参考以下文章