【问题标题】:Tricky SQL select棘手的 SQL 选择
【发布时间】:2014-09-16 18:14:56
【问题描述】:

我有一个消息表,该表包含以下列:

id | fromUserId | toUserId | sentDate | readDate | message | subject | fromUserDeleted(bit) | toUserDeleted(bit)

现在我需要在每次转换中选择第一条消息,无论它来自当前用户还是发往当前用户。更复杂的是,我需要排除当前用户删除的消息,因此如果消息来自当前用户,则 fromUserDeleted 必须为 0,如果消息来自另一个用户,则 toUserDeleted 必须为 0。

我知道已经有很多关于如何在群组中选择第一个帖子的示例,但这有点复杂。当前用户可能在 toUserId 或 fromUserId 中,删除的列也是如此。

这是我尝试过的:

SELECT 
    m1.*, 
    (SELECT count(*) FROM mail m3 WHERE m3.fromUserId=m1.fromUserId AND m3.toUserId=m1.toUserId AND m3.toUserDeleted = 0) as messageCount, 
    (SELECT count(*) FROM mail m4 WHERE m4.toUserId=15 AND m4.readDate is null AND m4.toUserDeleted=0) as messagesNotRead 
FROM 
    mail m1 
LEFT JOIN mail m2 ON 
    ((m1.fromUserId = m2.fromUserId) and
    m2.)
WHERE 
    m2.id IS NULL AND 
    (m1.toUserId = 15 OR m1.fromUserId = 15) 
ORDER BY 
    m1.sentDate DESC;

还有:

SELECT 
    * 
FROM 
    mail m1
WHERE
    ((m1.fromUserId = 15 AND m1.fromUserDeleted=0) OR (m1.toUserId = 15 AND m1.toUserDeleted=0)) AND
    m1.id = (SELECT m2.id FROM mail m2 WHERE m2.fromUserId = 15 OR m2.toUserId = 15 OR m2.fromUserId = m1.fromUserId OR m2.fromUserId = m1.toUserId OR m2.toUserId = m1.fromUserId OR m2.toUserId = m1.toUserId order By m2.sentDate desc limit 0,1)
Order by m1.sentDate DESC

这些都不能满足我的需要。请帮忙!

如果需要创建存储过程也没关系。

重要提示:这是我的 MySQL

编辑1:

请看这个例子:http://sqlfiddle.com/#!2/6a2ef/3

【问题讨论】:

  • 你能用测试数据和数据库结构准备一个 sql fiddle 吗?还包括您想要为该数据获得的理想结果。更好,如果它是最小的,包括所有可能的情况。
  • 只有 SendDate 重要,而 readDate 对查询不重要?
  • @user4035 我会试试的。
  • @Rajesh readData 大多数都在选择中,但它不适合选择逻辑。
  • 什么是“消息”。如果您的 ID 列是自动递增的,并且邮件可能是正文并且在收件人/收件人之间发生变化,那么标识该邮件 ID 序列 5 的内容是来自原始邮件 ID 2 的响应。主题是否可以像电子邮件一样更改通过转发和回复?这将打破这方面的共同点。

标签: mysql sql stored-procedures join


【解决方案1】:

执行 UNPIVOT 以获取同一列下的 fromUSerId、toUserId,以便我们可以根据 sentDate 选择正确的 userId。

SELECT T.*

FROM
(
    SELECT *,

           ROW_NUMBER() OVER ( PARTITION BY userVal ORDER BY sentDate DESC) as seq
    FROM
    (SELECT 
            *

     FROM msg
     WHERE (fromUserId = @userID AND fromUserDeleted = 0 ) 
           OR  (toUserId = @UserID AND toUserDeleted = 0)

    )p
    unpivot
    ( userVal for UserId in ( fromUserId, toUserId)
    )as unpvt
) T
WHERE seq =1 

【讨论】:

  • 这比我习惯的要高级一些。我已经尝试过脚本(使用正确的 userId),但在附近遇到语法问题:'(PARTITION BY userVal ORDER BY sentDate DESC)as seq FROM (SELECT '
  • 我用的是MS SQL,你的RDBMS是mysql吗?
  • 是的,对不起,它的 MySQL,我有一个 MySQL 标签,但我当然应该在我的帖子中提到它。
【解决方案2】:

感谢您的反馈。希望这能满足您的需求:

DECLARE @UserID INT
SELECT @UserID = 15

SELECT *
FROM (
    SELECT UserID, ConversationWithUserID, sentDate, readDate, [message], [subject], ROW_NUMBER() OVER (PARTITION BY ConversationWithUserID ORDER BY sentDate ASC) AS MessageOrder
    FROM (
        SELECT id, fromUserId AS UserID, toUserId AS ConversationWithUserID, sentDate, readDate, [message], [subject]
        FROM dbo.mail
        WHERE fromUserID = @UserID AND fromUserDeleted = 0
        UNION
        SELECT id, toUserId AS UserID, fromUserId AS ConversationWithUserID, sentDate, readDate, [message], [subject]
        FROM dbo.mail
        WHERE toUserId = @UserID AND toUserDeleted = 0
    ) x
) y
WHERE MessageOrder = 1
ORDER BY y.UserID, y.ConversationWithUserID

【讨论】:

  • 这将选择当前用户参与的并且未被他/她删除的所有消息。我需要的是来自所有用户的每次对话的最后一封邮件的列表。因此,在当前用户和用户 A 之间,即使有 100 条消息,我们也应该只获取最新消息。当前用户和用户 B 也是如此。
  • 那么如何确定对话呢?我们是否假设所有来回消息都是一次对话?
  • 是的,对话是当前用户到UserId或fromUserId的所有消息。
猜你喜欢
  • 2012-11-24
  • 2015-08-07
  • 1970-01-01
  • 2018-03-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-01-12
  • 2014-12-16
相关资源
最近更新 更多