检查 MySQL 如果行不存在,则插入(没有唯一键)

check MySQL if row is not exist, then insert (Without unique key)

我们有 2 个这样的 table:

1:帖子

ID    Title    Hits
1    Title 1    4
2    Title 2    7
3    Title 3    19
4    Title 4    8

2:命中

ID    PostID     IP
1       2     5.9.9.45
2       3     5.9.9.45
3       2     72.5.4.9
4       4     5.9.9.45

现在我们需要一个查询来检查 'hits' table 中是否不存在具有特定 PostID 和 IP 地址的行,插入一个新行并增加 posts.Hits 个单位(这是一个计数器)。

我们测试了这个查询:

INSERT INTO table (field) VALUES (value) ON DUPLICATE KEY UPDATE field=value

但是如您所见,IP 和 PostID 不能是唯一键。他们可以为不同的用户复制。 如果没有PostID+IP,有没有办法在一次查询中插入和更新?

您只需要在 两个 列而不是一个列上有唯一的 index/constraint:

create unique index unq_hits_postid_ip on hits(postid, ip);

那你可以用on duplicate key update.

但是,这将适用于 one table。在 another table 中递增计数器是一个奇怪的设计。为什么不在 hits 中设置计数器?如果您必须增加另一个 table,那么您将需要一个触发器。

要让每个 post 拥有唯一的 ip,你就像@gordon-linoff 说的那样:

create unique index unq_hits_postid_ip on hits(postid, ip);

然后你可以使用下面的语法来"ignore"插入:

insert into hits (postid, ip) values (2,'5.9.9.45') on duplicate key update id=id;

然后您可以使用触发器来确保在插入 ip 时更新命中列:

DELIMITER /

CREATE TRIGGER trg_ai_hits AFTER INSERT ON hits
  FOR EACH ROW
BEGIN
  UPDATE posts SET hits = hits + 1 WHERE id = NEW.postid;
END;
/

DELIMITER ;

虽然我自己不会这样设计,但我根本不会跟踪 table 中的点击数!获取点击次数是您可以在运行时使用 SQL.

轻松完成的事情

要计算特定 post 的点击次数(您需要此处 posts.title 的索引):

select 
count(1) as hits 
from posts p 
join hits h on p.id = h.postid
where p.title = 'Title 2';

要获得多个 post 的点击率,您可以使用 GROUP BY 子句:

select 
p.title, 
count(1) as hits 
from posts p 
join hits h on p.id = h.postid
where p.title in ('Title 2', 'Title 3')
group by p.title
order by hits desc;

另外,我认为您将同一个 IP 存储多次是件好事。使用您当前的设计,例如,您可以检查 IP 号码访问您的站点的次数:

select 
ip, 
count(postid) access_number 
from hits 
group by ip
order by access_number desc;