HoneySQL 不能处理 WHERE 子句中的复合键?

Posted

技术标签:

【中文标题】HoneySQL 不能处理 WHERE 子句中的复合键?【英文标题】:HoneySQL can't deal with compound key in WHERE clause? 【发布时间】:2019-02-19 18:42:44 【问题描述】:

我无法让 HoneySQL 发出允许我在 WHERE 子句中使用复合键的 SQL。

我想要得到的东西: SQL:

SELECT field_id, layer, event_date, is_deleted
FROM event
WHERE 
  field_id in ('1325629', '1627236', '1673576') AND
  layer in ('fha.raw') AND
  (field_id,layer,event_date) > ('1627236','fha.raw', '2018-07-23 09:45:07.6-07')
ORDER BY field_id, layer, event_date;

HoneySQL:

(-> (sqlh/select :field_id :layer :event_date :is_deleted)
    (sqlh/from :event)
    (sqlh/merge-where [:in :field_id field-ids])
    (sqlh/merge-where (cond (not-empty layers) [:in :layer layers]))
    (sqlh/merge-where [:> 
                       [:field_id :layer :event_date] 
                       ["1627236" "fha.raw" (c/from-string "2018-07-23T09:45:07.6-07:00")]])
    (sqlh/order-by :field_id :layer :event_date)
    sql/format)

HoneySQL 正在产生一些无法工作的东西

["SELECT field_id, layer, event_date, is_deleted FROM event WHERE (((field_id in (?, ?, ?)) AND (layer in (?, ?, ?, ?))) AND field_id(layer, event_date) > 1627236(?, ?)) ORDER BY field_id, layer, event_date"
 "1325629"
 "1627236"
 "1673576"
 "fha.abs"
 "fha.rank"
 "fha.true-color"
 "fha.raw"
 "fha.raw"
 #object[org.joda.time.DateTime 0x4fa79ee8 "2018-07-23T16:45:07.600Z"]]


...它在 WHERE 子句中隐藏了我的复合键,错误地构建了一个函数调用或其他东西:field_id(layer, event_date) 而不是(field_id, layer, event_date)

我该如何进行这项工作?

这与我之前在 ORDER BY 子句 (How can I make HoneySQL handle order by as a compound key?) 中尝试执行相同操作时提出的问题有关。事实证明,在复合键方面从未真正得到解决,但确实允许我在其中一个字段上对 DESC 进行排序。换句话说,我还没有找到如何让 HoneySQL 在 WHERE 或 ORDER BY 子句中执行复合键。

我可以使用一点方向。

【问题讨论】:

c/from-string 来自哪里? @myguidingstar 那是[clj-time.coerce :as c] 【参考方案1】:

与大多数 SQL 抽象一样,HoneySQL 仅适用于标准情况。我相信现在是使用raw 声明的好时机。它按原样插入 SQL 语句,而不使用函数或标记对其进行预处理:

(sql/raw "@var := foo.bar")
#sql/raw "@var := foo.bar"

在你的情况下,它只是:

...
(sqlh/merge-where
  #sql/raw "(field_id,layer,event_date) > ('1627236','fha.raw', '2018-07-23 09:45:07.6-07')")
...

你很好。

当然,永远不要将用户的输入传递到原始 SQL 语句中。

【讨论】:

【参考方案2】:

您可能需要考虑 Walkable,这是另一个具有更具表现力的语言的 SQL 库 https://walkable.gitlab.io/s-expressions.html

例如,这是您翻译成 Walkable 的查询:

(let [field-ids     [1 2 3]
      layers        ["a" "b" "c"]
      layer-filters (when (not-empty layers) `([:in :layer ~@layers]))]
  `[(:event/all :filters  [:and [:in :event/field-id ~@field-ids]
                            ~@layer-filters
                            [:> [:tuple :event/field-id :event/layer :event/event-date]
                             [:tuple "1627236" "fha.raw" "2018-07-23T09:45:07.6-07:00"]]]
                 :order-by [:event/field-id :event/layer :event/event-date]
                [:event/field-id :event/layer :event/event-date :event/is-deleted])])

【讨论】:

以上是关于HoneySQL 不能处理 WHERE 子句中的复合键?的主要内容,如果未能解决你的问题,请参考以下文章

如何使 HoneySQL 处理顺序作为复合键?

深入理解CQL中的Where子句

在oracle中where 子句和having子句中的区别

为啥我不能使用与 JPA 2.1 中的实体类型匹配的 TYPE-WHERE 子句查询实体?

oracle中where子句和having子句中的区别

oracle中where 子句和having子句中的区别