【问题标题】:How to query a complex boolean condition from MySQL table如何从 MySQL 表中查询复杂的布尔条件
【发布时间】:2012-08-09 11:10:56
【问题描述】:

我有下表用于个人消息:

id*    sender*    recipient* del_by_rec del_by_send
-+----------+-------------+-----------+-----------+
 2     tom        beth            0          1
 5     tom        josh            0          1
 5     tom        chris           1          1
 7     ashley     burt            1          0
 8     jenna      tom             1          0
 8     jenna      ashley          0          0
 8     jenna      jenna           1          0
10     ashley     burt            0          0

在哪里

  • id 是消息 ID,
  • senderrecipient 是用户登录,
  • sender 对消息 id 是唯一的
  • 一条消息id可以有多个recipient
  • del_by_rec 如果邮件已被收件人从其收件箱中删除,则为 1 并且
  • del_by_send 如果邮件已被发件人从其发件箱中删除,则为 1。
  • id-sender-recipient是主键,并且
  • id 引用另一个包含该消息的表中的主键 id

一旦当前用户决定这样做,我需要确定消息是否可以安全地从表中删除

来自收件人的收件箱

  1. 如果发件人已经从他的发件箱中删除了邮件(del_by_send = 1);和
  2. 如果此用户是唯一尚未从其收件箱中删除此邮件的收件人(del_by_rec = 0 对于此用户,del_by_rec = 1 对于所有其他收件人。)

或来自发件人的发件箱

  1. 如果所有收件人都已从其收件箱中删除此邮件(del_by_rec = 1 表示此邮件的所有收件人)。

否则,当前用户只需将其相应的del_by_recdel_by_send 标志设置为1,即可将此消息标记为删除。

有没有办法有效地查询这个条件

  1. 查看当前消息的当前用户;或
  2. 当前用户批量删除多条消息(我正在考虑针对这种情况返回多行结果)。

返回一个 boolean/int 真是太棒了。

看在我的份上,我无法通过此查询(假设用户是 ashley,她想从收件箱中删除消息 8):

SELECT (
    (SUM(del_by_send) > 0) # sender has deleted (at least 1)
    && ((SUM(del_by_rec) + 1) >= COUNT(id)) # only 1 recipient has not deleted yet
    && ((SELECT del_by_rec FROM msg_meta WHERE recipient = 'ashley' AND id = 8) = 0) # and that recipient is this user
)
FROM msg_meta
WHERE id = 8
GROUP BY id
  1. 这似乎可以胜任,但是否有点矫枉过正?
  2. 这对于多个消息ids 会失败,以避免昂贵的foreach。我为收件人burt 尝试了WHERE id IN (7,10),但我无法将它完全用于子查询..

帮助。谢谢大家。。

【问题讨论】:

    标签: mysql boolean conditional-statements


    【解决方案1】:

    我的建议是在消息级别使用子查询来获取您想要的信息,然后对此应用逻辑。以下查询接近:

    select id, (case when sum_del_by_send > 0 and (num_rec - sum_del_by_rec) <= 1
                     then 'Y'
                     else 'N'
                end) as IsSafeToDelete
    from (select id,
                 sum(del_by_send) as sum_del_by_send,
                 sum(del_by_rec) as sum_del_by_rec,
                 count(*) as num_rec
          from msg_meta
          group by id
         ) m
    

    这不考虑当前收件人。这个变体可以:

    select id, (case when sum_del_by_send > 0 and (num_others - sum_del_by_others) = 1
                     then 'Y'
                     else 'N'
                end) as IsSafeToDelete
    from (select id,
                 sum(del_by_send) as sum_del_by_send,
                 sum(case when recipient <> @RECIPIENT then del_by_rec end) as sum_del_by_others,
                 sum(case when recipient <> @RECIPIENT then 1 else 0 end) as num_others,
                 count(*) as num_rec
          from msg_meta
          group by id
         ) m
    

    这会一次处理所有消息。要处理特定的消息 id,只需将子查询中的“group by id”替换为:

    where id = @ID
    

    (@RECIPIENT 和@ID 是您要为其自定义查询的值。)

    【讨论】:

    • 哇,你是个传奇!史诗感谢! :D 我确实必须在 group by id 之前添加 where id in (...) 而不是替换它以定位超过 1 条记录。没关系,对吧?再次,哇。
    • 是的,添加一个 where 子句来选择多个 id 就可以了。
    【解决方案2】:

    想法 1:
    反转布尔值(将列称为保留或保存),先更新用户的删除,然后执行:

    SELECT id , SUM(del_by_send) + SUM(del_by_rec)
    FROM msg_meta
    WHERE id = 8
    GROUP BY id
    

    第二列所有为0的记录都是可删除的。

    想法 2:
    您可以通过 2 个步骤和一个子查询来完成(对于 1 个 id 可行,但可能会很慢)
    第 1 步:更新 1 个或多个消息 ID 的删除标志(通过接收或发送)。
    第 2 步:

    SELECT id 
    FROM msg_meta t
    WHERE t.id = 8
    AND NOT EXISTS(
      SELECT id
      FROM msg_meta t2
      WHERE t.id = t2.id
      AND (t2.del_by_rec = 0 OR t2.del_by_sent = 0)
    )
    

    也许其中 1 个可能会给您提供您需要的想法或想法 3 的火花;)

    【讨论】:

      【解决方案3】:

      多么有据可查的帖子...(我认为它们都像您的一样。)...

      我看到每条消息只能有一个发件人...那么为什么不将发件人的登录名和 del_by_send 标志放在消息表中呢?

      当发件人决定删除邮件时,这将节省大量时间,只更新一行。并且通过只记录每条消息的发件人姓名一次来占用大量空间...

      这应该已经加快了速度,因为您的表格会更轻,并且更新不会超过一行。

      (这将更接近规范化标准的建议。查看http://en.wikipedia.org/wiki/Database_normalization 了解有关数据库规范化的更多信息)

      为了简化您对安全删除的要求,我会在消息表中记录与该消息相关的人数。 (例如,对于消息 ID 5,people_count 将是 3(Tom、Josh 和 Chris)。每次用户(发送者或接收者)删除消息时,递减该计数器。当计数器降至 0 时,删除是安全的消息。

      希望这能...

      【讨论】:

      • 哈哈,谢谢,@cptHammer。肯定会解决的,我知道我制作元表的方式有些不对劲。这就是披萨和 3 小时睡眠对人类的影响。哈哈。让我知道你是否想出更多智慧。谢谢
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-06-26
      相关资源
      最近更新 更多