4

我需要一个消息列表,其中每一个都是当前用户和其他用户之间的“对话”中的最新消息。

这个问题中描述了相同的查询

我到目前为止的代码是:

t1 = Arel::Table.new(:messages, :as => 't1')
t2 = Arel::Table.new(:messages, :as => 't2')

convs1 = t1.
          project(
                  t1[:receiver_user_id].as('other_user_id'), 
                  t1[:receiver_user_id].as('receiver_user_id'), 
                  t1[:sender_user_id].as('sender_user_id'), 
                  t1[:created_at].as('created_at')
                 ).
          where(t1[:sender_user_id].eq(user.id))

convs2 = t2.project(
                  t2[:sender_user_id].as('other_user_id'), 
                  t2[:receiver_user_id].as('receiver_user_id'), 
                  t2[:sender_user_id].as('sender_user_id'), 
                  t2[:created_at].as('created_at')
                 ).
          where(t2[:receiver_user_id].eq(user.id))

conv = convs1.union(convs2)

首先,我收到一个错误:

ActiveRecord::StatementInvalid: Mysql2::Error: You have an error in your SQL syntax; check \
  the manual that corresponds to your MySQL server version for the right syntax to use near \
  'UNION SELECT `t2`...

如果我在下面生成的 sql 中手动将“UNION”替换为“UNION ALL”,则此方法有效。上述代码中的 conv.to_sql 产生:

SELECT `t1`.`receiver_user_id` AS other_user_id, 
       `t1`.`receiver_user_id` AS receiver_user_id, `
        t1`.`sender_user_id` AS sender_user_id, 
       `t1`.`created_at` AS created_at 
  FROM `messages` `t1` 
 WHERE `t1`.`sender_user_id` = 50 
UNION 
SELECT `t2`.`sender_user_id` AS other_user_id, 
       `t2`.`receiver_user_id` AS receiver_user_id, 
       `t2`.`sender_user_id` AS sender_user_id, 
       `t2`.`created_at` AS created_at 
  FROM `messages` `t2` 
 WHERE `t2`.`receiver_user_id` = 50

知道为什么会出现 MySQL UNION 错误。它是一个arel错误吗?其次,非常感谢您对完成查询的任何帮助。

更新: 使用 Arel::Nodes::Union.new 有效

4

4 回答 4

3

我认为这更可能是 mysql 故障,这是一个 mySQL 错误文本。这里讨论了类似的东西,但不完全是这个问题。

尝试迁移到另一个 sql server,然后再次检查,或者如果union all有效,则使用

conv = convs1.union(convs2, :all)

基于文档。

于 2012-08-17T15:35:21.973 回答
0

问题实际上是sql中的括号。如果我运行它会起作用:

Message.find_by_sql conv.to_sql.delete('()')

删除前导“(”和尾随“)”

奇怪..我不知道如何链接它来完成查询。(Arel::Nodes::Union 没有 group 方法)。这是 Rails 3.1.4

于 2012-08-21T09:29:14.093 回答
0

我有一个类似的问题并解决如下:

  def last_messages
    Message.find_by_sql("
          SELECT  messages.*,
                  (IF(recipient_id = #{id}, 0,1)) as outlast,
                  users.avatar_name,
                  users.name 
          FROM messages 
          INNER JOIN users 
              ON users.id=(IF(recipient_id = #{id}, sender_id,recipient_id))
          WHERE messages.id IN 
              ( SELECT max(id)
                FROM messages
                WHERE recipient_id = #{id} OR sender_id = #{id}
                GROUP BY (IF(recipient_id = #{id}, sender_id, recipient_id))
              )
          ORDER BY messages.id DESC")
  end
于 2013-02-25T20:27:40.503 回答
0

这是我最后使用的代码

all_msgs = Message.where("messages.sender_user_id = ? OR messages.receiver_user_id = ?",
                                     user.id, user.id)

msg_ids = all_msgs.select("sender_user_id, receiver_user_id, max(id) as max_id")
.group(:sender_user_id, :receiver_user_id).map { |m| m.max_id }

all_msgs = all_msgs.where(:id => msg_ids)
于 2013-04-23T14:55:17.110 回答