AR/Arel - 我如何编写查询来选择列的条件 CONCAT

发布于 2025-01-10 10:27:33 字数 679 浏览 2 评论 0原文

我有一个模型方法,如果用户保存了真实姓名,则有条件地连接用户的用户名(“登录”)和真实姓名 - 否则它只显示用户名。我想在 ActiveRecord 或 Arel 中重写查询。

看起来我应该使用 Arel::Nodes::NamedFunction。但我不明白如何使用命名函数进行条件连接。 (Arel 知道“if”吗?我在文档中找不到任何参考。)

  def primer_values
    connection.select_values(%(
      SELECT CONCAT(users.login,
                    IF(users.name = "", "", CONCAT(" <", users.name, ">")))
      FROM users
      ORDER BY IF(last_login > CURRENT_TIMESTAMP - INTERVAL 1 MONTH,
                  last_login, NULL) DESC,
                contribution DESC
      LIMIT 1000
    )).uniq.sort
  end

ORDER BY 中也有类似的条件。

I've got a model method that conditionally concatenates the user's username ("login") and real name, if they've saved a real name - otherwise it just shows the username. I'd like to rewrite the query in ActiveRecord or Arel.

It looks like I should use an Arel::Nodes::NamedFunction. But i don't understand how to do the conditional concatenation with a named function. (Does Arel know about "if"? I can't find any reference in the docs.)

  def primer_values
    connection.select_values(%(
      SELECT CONCAT(users.login,
                    IF(users.name = "", "", CONCAT(" <", users.name, ">")))
      FROM users
      ORDER BY IF(last_login > CURRENT_TIMESTAMP - INTERVAL 1 MONTH,
                  last_login, NULL) DESC,
                contribution DESC
      LIMIT 1000
    )).uniq.sort
  end

There's also similarly a conditional in ORDER BY.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

挽清梦 2025-01-17 10:27:33

虽然我通常讨厌 Rails 中的原始 SQL,但考虑到这种用法,我会保留它原样。尽管我可能会将其更改为更惯用的内容。

User
  .order(
    Arel.sql("IF(last_login > CURRENT_TIMESTAMP - INTERVAL 1 MONTH,last_login, NULL)").desc,
    User.arel_table[:contribution].desc)
  .limit(1000)
  .pluck(Arel.sql(
    'CONCAT(users.login,
      IF(users.name = "", "", 
        CONCAT(" <", users.name, ">")))'))
  .uniq.sort

将其转换为 Arel 而不将其抽象为自己的对象会严重损害可读性。

这么说只是为了给你一个想法;第一部分是 3 个 NamedFunction

  1. CONCAT
  2. IF
  3. CONCAT
Arel::Nodes::NamedFuction.new(
  "CONCAT",
  [User.arel_table[:name],
   Arel::Nodes::NamedFuction.new(
     "IF",
     [User.arel_table[:name].eq(''),
      Arel.sql("''"),
      Arel::Nodes::NamedFuction.new(
         "CONCAT",
         [Arel.sql("' <'"),
          User.arel_table[:name],
          Arel.sql("'>'")]
      )]
  )]
)

A NamedFunctionFUNCTION_NAME(ARG1,ARG2,ARG3) 的构造函数,因此任何 SQL使用此语法可以使用 NamedFunction 创建,包括空函数,如 NOW() 或其他语法,如横向(查询)

While generally I abhor Raw SQL in rails given this usage I'd leave it as is. Although I might change it to something a bit more idiomatic like.

User
  .order(
    Arel.sql("IF(last_login > CURRENT_TIMESTAMP - INTERVAL 1 MONTH,last_login, NULL)").desc,
    User.arel_table[:contribution].desc)
  .limit(1000)
  .pluck(Arel.sql(
    'CONCAT(users.login,
      IF(users.name = "", "", 
        CONCAT(" <", users.name, ">")))'))
  .uniq.sort

Converting this to Arel without abstracting it into an object of its own will damage the readability significantly.

That being said just to give you an idea; the first part would be 3 NamedFunctions

  1. CONCAT
  2. IF
  3. CONCAT
Arel::Nodes::NamedFuction.new(
  "CONCAT",
  [User.arel_table[:name],
   Arel::Nodes::NamedFuction.new(
     "IF",
     [User.arel_table[:name].eq(''),
      Arel.sql("''"),
      Arel::Nodes::NamedFuction.new(
         "CONCAT",
         [Arel.sql("' <'"),
          User.arel_table[:name],
          Arel.sql("'>'")]
      )]
  )]
)

A NamedFunction is a constructor for FUNCTION_NAME(ARG1,ARG2,ARG3) so any SQL that uses this syntax can be created using NamedFunction including empty functions like NOW() or other syntaxes like LATERAL(query).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文