Clojure HoneySQL - 如何在连接后将字符串值聚合到单行中?

Posted

技术标签:

【中文标题】Clojure HoneySQL - 如何在连接后将字符串值聚合到单行中?【英文标题】:Clojure HoneySQL - How to aggregate a string value after a join into a single row? 【发布时间】:2020-11-30 05:00:43 【问题描述】:

我正在执行以下查询,该查询连接 3 个表以拉回锻炼以及与它们关联的标签。

(db/query :select [:workouts.id :workouts.name :tag.tag_name]
             :from   [:workouts]
             :left-join [[:workout_tags :workout_tag] [:= :workout_tag.workout_id :workouts.id]
                         [:tags :tag] [:= :tag.tag_id :workout_tag.tag_id]]
             :where  [:= :workouts.id 1]))

这将返回以下内容:

(:id 1, :name "Short", :tag_name "cardio" 
 :id 1, :name "Short", :tag_name "No weights")

理想情况下,我希望将tag_name 组合到一个字段中返回给最终用户一个结果。比如:

:id 1, :name "Short", :tag_name ["cardio" "No weights"] 

事实证明我可以很容易地做到这一点,但我想看看是否有一个内置的 mysql 函数可以完成我想要完成的事情。似乎GROUP_CONACT 可能会做我正在寻找的东西,但我似乎无法让它在 HoneySQL 的上下文中工作。

【问题讨论】:

【参考方案1】:

以下应该接近你需要的:

  (require '[honeysql.core :as hc])
  (hc/format :select [:workouts.id :workouts.name [(hc/call :group_concat :tag.tag_name) :tag_name]]
              :from   [:workouts]
              :left-join [[:workout_tags :workout_tag] [:= :workout_tag.workout_id :workouts.id]
                          [:tags :tag] [:= :tag.tag_id :workout_tag.tag_id]]
              :where  [:= :workouts.id 1]
              :group-by [:tag.tag_name])

生成以下 SQL:

SELECT workouts.id, workouts.name, group_concat(tag.tag_name) AS tag_name
FROM workouts
LEFT JOIN workout_tags workout_tag ON workout_tag.workout_id = workouts.id
LEFT JOIN tags tag ON tag.tag_id = workout_tag.tag_id
WHERE workouts.id = ?
GROUP BY tag.tag_name

你没有展示你尝试了什么或失败了什么,这肯定有助于我们确定我们应该建议什么作为答案。

【讨论】:

【参考方案2】:

事后我会这样做:

  (let [data    [:id 1, :name "Short", :tag_name "cardio"
                 :id 1, :name "Short", :tag_name "No weights"
                 :id 2, :name "Long", :tag_name "Tall"
                 :id 2, :name "Long", :tag_name "Hills"]
        grouped (group-by :id data)
        id-tags (vec (for [[id data-maps] grouped]
                       (let [tags (mapv :tag_name data-maps)]
                         :id id :tags tags)))]
    (is= id-tags
      [:id 1, :tags ["cardio" "No weights"]
       :id 2, :tags ["Tall" "Hills"]]))

中间结果grouped看起来像

grouped => 
1
 [:id 1, :name "Short", :tag_name "cardio"
  :id 1, :name "Short", :tag_name "No weights"],
 2
 [:id 2, :name "Long", :tag_name "Tall"
  :id 2, :name "Long", :tag_name "Hills"]

请参阅my favorite template project 了解完整的配置详情。

【讨论】:

以上是关于Clojure HoneySQL - 如何在连接后将字符串值聚合到单行中?的主要内容,如果未能解决你的问题,请参考以下文章

HoneySQL 中的联合

Honeysql RDBMS 是不可知的吗?

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

honeysql merge-where 构建大型查询

如何关闭 clojure ring web 应用程序中的 Hikari 连接池部署到 elasticbeanstalk 中的 tomcat

设置 .emacs.d 文件夹后如何从 Emacs 运行 Clojure REPL