1

我有一个投票系统,我正在尝试为 MySQL 编写一个查询,该查询将检测哪些投票已完成,以便可以将电子邮件发送给投票的创建者。当(1)他们的时间用完(已经很容易解决)或(2)当所有选民都投票时,投票就完成了。

有两个表与此相关。第一个表是“votes”,其中描述了每个投票并具有唯一的“vote_id”。第二张表是“票”。在创建投票时,每个参与者都创建了一张票(其中包含一些身份验证信息)。每张票都有一个“vote_id”字段,对应于“votes”表中的字段。所以基本上,当人们投票时,他们相应的票就会从票表中删除。这意味着给定“vote_id”的“tickets”中的行数对应于未投票的人数。

起初我去做这样的事情:

SELECT votes.vote_id
FROM votes, tickets
WHERE votes.vote_id=tickets.vote_id
AND (votes.completion_timestamp < NOW())
HAVING (COUNT(tickets.vote_id) = 0)

但后来我意识到......因为“votes.vote_id=tickets.vote_id”行......我想这意味着没有未完成票的投票将被忽略。我可以想到很多低效的方法来做到这一点,但我想在 MySQL 中有一种方法可以做到这一点?

问题的概括总结:给定两个具有公共字段 F 的表 A 和 B,我如何找到 A 中不存在于 B 中的所有 F?

4

2 回答 2

3

要在 MySQL 中有效地做到这一点,需要一个技巧:

select v.*
from votes v
where votes.completion_timestamp < NOW() and
      not exists (select 1 from tickets t where t.vote_id = v.vote_id)

您拥有的 SQL 不太正确。以下版本应该可以工作:

SELECT distinct votes.vote_id
FROM votes left outer join
     tickets
     on votes.vote_id=tickets.vote_id
where votes.completion_timestamp < NOW()) and
      tickets.vote_id is null 

在 MySQL 文档 (http://dev.mysql.com/doc/refman/5.0/en/subquery-optimization-with-exists.html) 中广泛讨论了 EXISTS 与 IN 与子查询的使用。与左外连接的区别在于两件事。加入策略,增加 I/O。

我不知道 JOIN 策略是否与左外连接不同。我推测它不应该比 EXISTS 版本更糟。但是,第二点是左外连接创建了一个可能使行数成倍增加的输出集。EXISTS 版本无法做到这一点。

阅读文档后,以下内容可能会更有效:

select v.*
from votes v
where votes.completion_timestamp < NOW() and
      not exists (select 1 from tickets t where t.vote_id = v.vote_id limit 1)

限制应该使超出遇到的第一行的任何评估短路。

于 2012-08-22T15:23:45.903 回答
2

像这样的东西会返回你期望的结果:

select votes.vote_id
from votes
    left outer join tickets on votes.vote_id = tickets.vote_id
where tickets.ticket_id is null or votes.completion_timestamp < NOW()

这假定这tickets.ticket_idtickets表的主键并且不能为 NULL。
此查询通过执行从投票到票证的左外连接来利用这一事实,条件tickets.ticket_id必须为 NULL。tickets仅当该投票表中没有一张票时才会发生这种情况。

于 2012-08-22T15:23:10.803 回答