获取不存在的行

时间:2021-09-05 13:03:00

Title might sound strange but I'll try to explain the problem as easy as possible. Let's start with example. I got a table with 2 columns - id, ip. Let's say I got 3 rows with id 2,3,5. Now, I need to get any row that isn't between id 1 AND 5, which is clearly 1 and 4. Currently I'm stuck with this query:

标题可能听起来很奇怪,但我将尽可能简单地解释这个问题。让我们开始的例子。我有一个2列的表,id, ip。假设有3行id为2 3 5。现在,我需要得到任何不在id 1和5之间的行,显然是1和4。目前我被这个问题困住了:

SELECT * 
FROM `votes` 
WHERE ip = "1.1.1.1."  
AND question_id BETWEEN 1 AND 5

3 个解决方案

#1


2  

sounds bizarre but this is what many do.

听起来很奇怪,但很多人都是这么做的。

create a helper table. Use it for left joins

创建一个辅助表。将它用于左连接

create table amfn
(   -- All My Favorite Numbers  
    id int auto_increment primary key,
    theWhat char(1) null
)engine=MyIsam;   --  <----- somewhat important

insert amfn(theWhat) values (null),(null),(null),(null),(null),(null),(null),(null),(null),(null); -- 10
insert amfn(theWhat) select theWhat from amfn;
insert amfn(theWhat) select theWhat from amfn;
insert amfn(theWhat) select theWhat from amfn;
insert amfn(theWhat) select theWhat from amfn;
insert amfn(theWhat) select theWhat from amfn;
insert amfn(theWhat) select theWhat from amfn;
insert amfn(theWhat) select theWhat from amfn;
insert amfn(theWhat) select theWhat from amfn;
insert amfn(theWhat) select theWhat from amfn;
insert amfn(theWhat) select theWhat from amfn;
insert amfn(theWhat) select theWhat from amfn;
insert amfn(theWhat) select theWhat from amfn;
insert amfn(theWhat) select theWhat from amfn;
insert amfn(theWhat) select theWhat from amfn;
insert amfn(theWhat) select theWhat from amfn;
insert amfn(theWhat) select theWhat from amfn;
insert amfn(theWhat) select theWhat from amfn;

select count(*),min(id),max(id) from amfn;
+----------+---------+---------+
| count(*) | min(id) | max(id) |
+----------+---------+---------+
|  1310720 |       1 | 1310720 |
+----------+---------+---------+
1 row in set (0.00 sec)

Your Schema:

create table votes
(   question_id int not null,
    ip varchar(20) not null
);
insert votes (question_id,ip) values (1,'xxxx'),(2,'1.1.1.1'),(3,'1.1.1.1'),(4,'1.6.1.1'),(5,'1.1.1.1');

The Query:

select a.id,v.question_id,v.ip
from amfn a
left join votes v
on v.question_id=a.id and v.ip='1.1.1.1'
where a.id between 1 and 5 and v.question_id is null;
+----+-------------+------+
| id | question_id | ip   |
+----+-------------+------+
|  1 |        NULL | NULL |
|  4 |        NULL | NULL |
+----+-------------+------+
2 rows in set (0.00 sec)     <------------- boy that is fast

Edit (to show Conrad Frix the time differences).

My above approach to create 5242880 rows, 23.5 seconds. Conrad's approach, 168.5 seconds. I will stick with my approach :>

我上面的方法创建了5242880行,23.5秒。康拉德的方法,168.5秒。我将坚持我的方法:>

#2


1  

A really unusual request;

一个真的不同寻常的请求;

But you may get what you want by creating an auxiliary sequence of 1..5, then select all the ids from this sequence where there's no matching entry in the votes table.

但是你可以通过创建一个1的辅助序列来得到你想要的。然后从这个序列中选择所有的id,因为在投票表中没有匹配条目。

SELECT id 
FROM (
  SELECT 1 AS id UNION ALL 
  SELECT 2 UNION ALL 
  SELECT 3 UNION ALL 
  SELECT 4 UNION ALL 
  SELECT 5 UNION ALL 
) AS temp 
WHERE temp.id NOT IN (SELECT DISTINCT question_id FROM votes);

#3


1  

Ok, I find the solution -

我找到了解

I made new column for each question_id and all ip fields I filled with NULL, after that I use this logic in SQL query:

我为每个question_id和所有用NULL填充的ip字段新建了一个列,然后在SQL查询中使用这个逻辑:

SELECT question_id
FROM  `votes` 
WHERE (ip =  'NULL' OR ip = ?)
GROUP BY question_id
HAVING COUNT(*) - COUNT(DISTINCT question_id) = 0
ORDER BY RAND()
LIMIT 1

And in result I get one random row that haven't been used yet, because it searches for duplicates, and if any duplicates are found they are removed from search. I hope I wrote this understandable

结果,我得到了一个尚未使用的随机行,因为它搜索重复的,如果找到重复的,它们就从搜索中删除。我希望我写这篇文章是可以理解的

#1


2  

sounds bizarre but this is what many do.

听起来很奇怪,但很多人都是这么做的。

create a helper table. Use it for left joins

创建一个辅助表。将它用于左连接

create table amfn
(   -- All My Favorite Numbers  
    id int auto_increment primary key,
    theWhat char(1) null
)engine=MyIsam;   --  <----- somewhat important

insert amfn(theWhat) values (null),(null),(null),(null),(null),(null),(null),(null),(null),(null); -- 10
insert amfn(theWhat) select theWhat from amfn;
insert amfn(theWhat) select theWhat from amfn;
insert amfn(theWhat) select theWhat from amfn;
insert amfn(theWhat) select theWhat from amfn;
insert amfn(theWhat) select theWhat from amfn;
insert amfn(theWhat) select theWhat from amfn;
insert amfn(theWhat) select theWhat from amfn;
insert amfn(theWhat) select theWhat from amfn;
insert amfn(theWhat) select theWhat from amfn;
insert amfn(theWhat) select theWhat from amfn;
insert amfn(theWhat) select theWhat from amfn;
insert amfn(theWhat) select theWhat from amfn;
insert amfn(theWhat) select theWhat from amfn;
insert amfn(theWhat) select theWhat from amfn;
insert amfn(theWhat) select theWhat from amfn;
insert amfn(theWhat) select theWhat from amfn;
insert amfn(theWhat) select theWhat from amfn;

select count(*),min(id),max(id) from amfn;
+----------+---------+---------+
| count(*) | min(id) | max(id) |
+----------+---------+---------+
|  1310720 |       1 | 1310720 |
+----------+---------+---------+
1 row in set (0.00 sec)

Your Schema:

create table votes
(   question_id int not null,
    ip varchar(20) not null
);
insert votes (question_id,ip) values (1,'xxxx'),(2,'1.1.1.1'),(3,'1.1.1.1'),(4,'1.6.1.1'),(5,'1.1.1.1');

The Query:

select a.id,v.question_id,v.ip
from amfn a
left join votes v
on v.question_id=a.id and v.ip='1.1.1.1'
where a.id between 1 and 5 and v.question_id is null;
+----+-------------+------+
| id | question_id | ip   |
+----+-------------+------+
|  1 |        NULL | NULL |
|  4 |        NULL | NULL |
+----+-------------+------+
2 rows in set (0.00 sec)     <------------- boy that is fast

Edit (to show Conrad Frix the time differences).

My above approach to create 5242880 rows, 23.5 seconds. Conrad's approach, 168.5 seconds. I will stick with my approach :>

我上面的方法创建了5242880行,23.5秒。康拉德的方法,168.5秒。我将坚持我的方法:>

#2


1  

A really unusual request;

一个真的不同寻常的请求;

But you may get what you want by creating an auxiliary sequence of 1..5, then select all the ids from this sequence where there's no matching entry in the votes table.

但是你可以通过创建一个1的辅助序列来得到你想要的。然后从这个序列中选择所有的id,因为在投票表中没有匹配条目。

SELECT id 
FROM (
  SELECT 1 AS id UNION ALL 
  SELECT 2 UNION ALL 
  SELECT 3 UNION ALL 
  SELECT 4 UNION ALL 
  SELECT 5 UNION ALL 
) AS temp 
WHERE temp.id NOT IN (SELECT DISTINCT question_id FROM votes);

#3


1  

Ok, I find the solution -

我找到了解

I made new column for each question_id and all ip fields I filled with NULL, after that I use this logic in SQL query:

我为每个question_id和所有用NULL填充的ip字段新建了一个列,然后在SQL查询中使用这个逻辑:

SELECT question_id
FROM  `votes` 
WHERE (ip =  'NULL' OR ip = ?)
GROUP BY question_id
HAVING COUNT(*) - COUNT(DISTINCT question_id) = 0
ORDER BY RAND()
LIMIT 1

And in result I get one random row that haven't been used yet, because it searches for duplicates, and if any duplicates are found they are removed from search. I hope I wrote this understandable

结果,我得到了一个尚未使用的随机行,因为它搜索重复的,如果找到重复的,它们就从搜索中删除。我希望我写这篇文章是可以理解的