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

AR/Arel - How can i compose a query to SELECT a conditional CONCAT of columns

我有一个模型方法,它有条件地连接用户的用户名(“登录”)和真实姓名,如果他们保存了真实姓名 - 否则它只显示用户名。我想在 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 中也有类似的条件。

虽然通常我讨厌 rails 中的 Raw 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 NamedFunctions

  1. 连接
  2. 如果
  3. 连接
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() 或其他语法,如 LATERAL(query).