【问题标题】:How do I select unique from one of two fields? (that doesn't equal a certain value?)如何从两个字段之一中选择唯一的? (这不等于某个值?)
【发布时间】:2012-01-23 08:36:54
【问题描述】:

基本上我想要做的是选择一个用户之间的最新消息,他们接收或发送消息的任何人。这意味着我需要的唯一用户 ID 可能在 m_to 或 m_from 中。那么如何过滤搜索以从两个字段之一中选择唯一 ID,其中该字段不是主用户的 ID?我在这里说得通吗?

SELECT * FROM messages
WHERE m_to = '$user_id' OR m_from = '$user_id'
ORDER BY date

所以为了(尽量)清楚,我需要进行一个查询,该查询将为他们接收或发送消息的每个用户选择从主要用户接收或发送的最新消息。这样列表中就没有重复的用户。但是,由于这可能在 to 或 from 字段中,我不知道如何执行此操作。有人可以帮我看看吗?

编辑:好的,显然我不清楚。 $user_id 变量是登录用户的用户 ID。这意味着我需要来自不是 $user_id 的 m_from 或 m_to 字段的唯一消息

编辑:

如果我们正在运行此查询...

选择 用户, the_other_party, MAX(日期) AS max_date 从 ( 选择 CASE m_to WHEN 'IxjXgC' THEN m_to ELSE m_from END AS the_user, CASE m_from WHEN 'IxjXgC' THEN m_to ELSE m_from END AS the_other_party, 日期 来自消息 WHERE m_to = 'IxjXgC' 或 m_from = 'IxjXgC' ) 米 假设我们在数据库中有这些类别...

m_to    m_from     date
IxjXgC  ShJiMr   2012-01-22 01:20:37
ShJiMr  IxjXgC   2012-01-22 02:22:37
LhJiM1  IxjXgC   2012-01-22 03:23:37

然后我运行上面的查询,结果就变成了……

the_other_party     date
ShJiMr              2012-01-22 03:23:37

【问题讨论】:

    标签: mysql sql select unique


    【解决方案1】:

    我不会指责你懒惰(恐怕我在这方面并不比你好),但我同意 Andreas Rohde 的观点,即你应该努力将必要的列明确列为尽可能经常。这样做可能真的可以帮助您看到原本不太明显的解决方案,如果有的话。

    以您当前的问题为例。您需要一种 GROUP BY 查询,它会忽略用户作为发送者/接收者的状态。为什么,在一种情况下,您可以简单地将发送者替换接收者,反之亦然,而在另一种情况下保持不变。那么考虑一下:

    SELECT
      CASE m_to   WHEN '$user_id' THEN m_to ELSE m_from END AS the_user,
      CASE m_from WHEN '$user_id' THEN m_to ELSE m_from END AS the_other_party,
      date
    FROM messages
    WHERE m_to   = '$user_id'
       OR m_from = '$user_id'
    

    结果集将包含相关用户将始终返回为the_user,而另一方则始终返回为the_other_party 的行。

    当然,既然我们确保'$user'在同一列中返回,第一个CASE可以去掉:

    SELECT
      '$user_id' AS the_user,
      CASE m_from WHEN '$user_id' THEN m_to ELSE m_from END AS the_other_party,
      date
    FROM messages
    WHERE m_to   = '$user_id'
       OR m_from = '$user_id'
    

    也就是说,如果您需要该列。

    无论如何,您现在可以聚合上述查询的结果集,例如像这样:

    SELECT
      the_user,
      the_other_party,
      MAX(date) AS max_date
    FROM (
      SELECT
        CASE m_to   WHEN '$user_id' THEN m_to ELSE m_from END AS the_user,
        CASE m_from WHEN '$user_id' THEN m_to ELSE m_from END AS the_other_party,
        date
      FROM messages
      WHERE m_to   = '$user_id'
         OR m_from = '$user_id'
    ) m
    GROUP BY
      the_user,
      the_other_party
    

    您还可以将最后一个查询作为子选择加入到(messages.m_to = agg.the_user OR messages.m_from = agg.the_user) AND messages.date = agg.max_date 上的messages 以获取其余列。

    【讨论】:

    • 这对我理解这个问题有很大帮助,但是在尝试创建类似的解决方案数小时后,我仍然无法让它工作......当我尝试实施你的技术时具体来说,即使我尝试直接复制和粘贴,我也会不断收到错误消息,提示我的语法有问题。
    • @itdoell:我已经用完了逗号,我才注意到这一分钟。对不起!我现在已经更新了我的答案。
    • 谢谢,这对我们帮助很大。但是,我仍然遇到了一个主要问题。该查询仅返回一个结果(来自您发送消息或接收消息的所有用户)因此,虽然它将收件人/发件人分组在一起,但并不是对每个人都这样做。此外,它只是返回带有 the_other_party 的 max_date,而不管对方是否发送了该消息。稍后我会更新主要帖子的解释。
    • 糟糕,对不起,我不是要编辑你的帖子 =P 我是想编辑我自己的。
    • @itdoell:尽管我打算向您展示如何在这种情况下对数据进行分组,但我还是设法省略了 GROUP BY 子句。哦,好吧……再次抱歉,现在应该没事了。
    【解决方案2】:

    如果您只希望一个用户 $user_id 使用此功能,那么您的查询几乎完成了.. 只需将顺序颠倒到最新的优先 (DESC) 并将输出限制为 1

    SELECT * FROM messages 
    WHERE m_to = '$user_id' OR m_from = '$user_id' 
    ORDER BY date DESC 
    LIMIT 1
    

    回答编辑:

    SELECT * FROM messages 
    WHERE not (m_to = '$user_id' OR m_from = '$user_id') 
    ORDER BY date DESC 
    

    用户既是接收者又是发送者的消息


    如何与 $user_id 联系的人员列表

    SELECT DISTINCT IF(m_to=$user_id, m_from, m_to)
    FROM messages 
    WHERE m_to = '$user_id' OR m_from = '$user_id'
    ORDER BY date DESC 
    

    【讨论】:

    • 不,$user_id 是已登录用户的会话。
    • 但用户需要成为发送者或接收者。我只需要让他们发送消息或接收消息的人,而不是他们正在与之交谈的人的任何重复。
    • 好的,现在我知道你想要什么了... 3. 试试 ;)
    【解决方案3】:

    我想你想要这个:

    给定用户 A,返回与用户 A 有过对话的所有用户 B 的最新消息 M。

    以下语句将为您提供与用户 A 交换消息的每个用户 B 的最长时间:

    select
        m2.this_user,
        m2.other_user,
        max(m2.date) max_message_date
    from    
    (
        select
            m.*,
            IF(m.m_to = '$user_id', m.m_to, m.m_from) as this_user,
            IF(m.m_to = '$user_id', m.m_from, m.m_to) as other_user,
        from
            messages m
        where
            m.m_to = '$user_id'
            or m.m_from = '$user_id'
    ) m2
    group by
        m2.this_user,
        m2.other_user
    ;
    

    使用此信息,您可以通过加入messages 来获取完整的消息详细信息:

    select
        m3.*
    from
        messages m3
        inner join
        (
             select
             m2.this_user,
             m2.other_user,
             max(m2.date) max_message_date
         from    
         (
             select
                 m.*,
                 IF(m.m_to = '$user_id', m.m_to, m.m_from) as this_user,
                 IF(m.m_to = '$user_id', m.m_from, m.m_to) as other_user,
             from
                 messages m
             where
                 m.m_to = '$user_id'
                 or m.m_from = '$user_id'
         ) m2
         group by
             m2.this_user,
             m2.other_user
        ) d
            on  ((m3.m_to = d.this_user and m3.m_from = d.other_user) or
                 (m3.m_to = d.other_user and m3.m_from = d.this_user))
            and m3.date = d.max_message_date
    ;
    

    我很确定有一种不那么冗长的方法,但这应该可以帮助您入门。

    【讨论】:

      【解决方案4】:

      试试这个:

      SELECT * FROM messages WHERE m_to = '$user_id' 
      union
      SELECT * FROM messages WHERE m_from = '$user_id' 
      ORDER BY date desc Limit 1
      

      我认为这将解决您的问题。顺便说一句,不要使用* 进行此类查询。建议使用您想要从中获取值的列名。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-11-23
        • 1970-01-01
        • 2016-10-25
        • 1970-01-01
        • 1970-01-01
        • 2020-06-03
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多