2012-08-09 63 views
2

我已经为个人信息如下表:如何从MySQL表查询复杂的布尔条件

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
  • 可以有多于一个的recipient到消息id
  • 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. 当前用户批量删除多个邮件(我想这种情况下多行结果将被返回)。

返回布尔值/整数将会很棒。

对我的爱,我无法摆脱这种查询(假定用户是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. 这对于多个消息id s来说是不合格的,以避免昂贵的foreach。我试着WHERE id IN (7,10)收件人burt,但我无法完成它的子查询。

帮助。谢谢你们..

回答

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,只需更换“的ID组”与子查询:

where id = @ID 

(@RECIPIENT和@ID的意思是,你想自定义查询中的值)

+0

哇,你是一个传奇!史诗般的感谢! :D我不得不在'group by id'之前添加'where id in(...)',而不是将它替换为超过1条记录。没关系,对吧?再次,哇。 – 2012-08-09 17:20:04

+0

是的,添加一个where子句来选择多个id很好。 – 2012-08-09 18:02:16

1

理念1:
反转的布尔(拨打列类似保留或保存),更新用户的删除,然后再去做:

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

中的所有记录与第二列中的0是可删除的。

理念2:
你可以做2个步骤,用子查询(可行的1号,但它可能是很多慢)
第1步:更新删除的标志(或者通过REC或通过发送)为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火花;)

+0

非常感谢,克里斯托夫,将继续关注它。< – 2012-08-09 11:43:08

0

什么是有据可查的帖子...(我wiched他们都像你的。)...

我看到,每个消息只能有一个发送者...所以你为什么不把发送者的登录信息和del_by_send标志放在消息表中?

当发件人决定删除邮件时,这将节省相当多的时间只更新一行。并通过记录每个消息只发送一次发件人名称很多空间...

这应该已经加快了速度,因为您的表会更轻,并且更新永远不会改变更多的一行。

(这将是更接近什么是规范化的标准建议。检查http://en.wikipedia.org/wiki/Database_normalization有关数据库规范化的详细信息)

简化您的追求,安全缺失,我会在消息表中记录的人数与消息有关。 (例如,对于消息ID 5,people_count将为3(Tom,Josh和Chris)。每次用户(发送者或接收者)删除该消息时,将该计数器递减。当计数器下降到0时,可以安全地删除德消息。

希望这HEPS ...

+0

哈哈,谢谢,@ cptHammer。肯定会解决这个问题,我知道我是如何制作元表的......这是比萨和3小时的睡眠对人类的影响。大声笑。让我知道你是否更有智慧。谢谢 – 2012-08-09 12:19:36