我们如何找到 MySQL 中顺序编号的间隙?

发布于 2024-10-05 17:20:39 字数 276 浏览 4 评论 0原文

我们有一个数据库,其中有一个表,其值是从另一个系统导入的。有一个自增列,并且没有任何重复值,但有缺失值。例如,运行此查询:

select count(id) from arrc_vouchers where id between 1 and 100

应返回 100,但它返回 87。我可以运行一个查询来返回缺失数字的值吗?例如,可能存在 id 1-70 和 83-100 的记录,但没有任何 id 为 71-82 的记录。我想返回71、72、73等,

可以吗?

We have a database with a table whose values were imported from another system. There is an auto-increment column, and there aren’t any duplicate values, but there are missing values. For example, running this query:

select count(id) from arrc_vouchers where id between 1 and 100

should return 100, but it returns 87 instead. Is there a query I can run that will return the values of the missing numbers? For example, the records may exist for id 1-70 and 83-100, but there aren’t any records with id's of 71-82. I want to return 71, 72, 73, etc.

Is this possible?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(16

宁愿没拥抱 2024-10-12 17:20:39

更好的答案

JustPlainMJS 提供了一个更好的答案表现。

(不是尽可能快)答案

这是一个适用于任何大小的表(不仅仅是 100 行)的版本:

SELECT (t1.id + 1) as gap_starts_at,
       (SELECT MIN(t3.id) -1 FROM arrc_vouchers t3 WHERE t3.id > t1.id) as gap_ends_at
FROM arrc_vouchers t1
WHERE NOT EXISTS (SELECT t2.id FROM arrc_vouchers t2 WHERE t2.id = t1.id + 1)
HAVING gap_ends_at IS NOT NULL
  • gap_starts_at - 当前间隙中的第一个 id
  • gap_ends_at - 当前间隙中的最后一个 ID

A better answer

JustPlainMJS provided a much better answer in terms of performance.

The (not as fast as possible) answer

Here's a version that works on a table of any size (not just on 100 rows):

SELECT (t1.id + 1) as gap_starts_at,
       (SELECT MIN(t3.id) -1 FROM arrc_vouchers t3 WHERE t3.id > t1.id) as gap_ends_at
FROM arrc_vouchers t1
WHERE NOT EXISTS (SELECT t2.id FROM arrc_vouchers t2 WHERE t2.id = t1.id + 1)
HAVING gap_ends_at IS NOT NULL
  • gap_starts_at - first id in current gap
  • gap_ends_at - last id in current gap
活雷疯 2024-10-12 17:20:39

这正好帮助我找到超过 80k 行的表中的间隙:

SELECT
  CONCAT(z.expected, IF(z.got-1>z.expected, CONCAT(' thru ',z.got-1), '')) AS missing
FROM (
  SELECT
    @rownum:=@rownum+1 AS expected,
    IF(@rownum=YourCol, 0, @rownum:=YourCol) AS got
  FROM
    (SELECT @rownum:=0) AS a
    JOIN YourTable
    ORDER BY YourCol
  ) AS z
WHERE z.got!=0;

结果:

+------------------+
| missing          |
+------------------+
| 1 thru 99        |
| 666 thru 667     |
| 50000            |
| 66419 thru 66456 |
+------------------+
4 rows in set (0.06 sec)

请注意,expectedgot 列的顺序至关重要。

如果您知道 YourCol 不是从 1 开始,这并不重要,您可以替换

(SELECT @rownum:=0) AS a

(SELECT @rownum:=(SELECT MIN(YourCol)-1 FROM YourTable)) AS a

新结果:

+------------------+
| missing          |
+------------------+
| 666 thru 667     |
| 50000            |
| 66419 thru 66456 |
+------------------+
3 rows in set (0.06 sec)

如果您需要对丢失的 ID 执行某种 shell 脚本任务,您可以还可以使用此变体直接生成一个可以在 Bash 中迭代的表达式。

SELECT GROUP_CONCAT(IF(z.got-1>z.expected, CONCAT('$(',z.expected,' ',z.got-1,')'), z.expected) SEPARATOR " ") AS missing
FROM ( SELECT @rownum:=@rownum+1 AS expected, IF(@rownum=height, 0, @rownum:=height) AS got FROM (SELECT @rownum:=0) AS a JOIN block ORDER BY height ) AS z WHERE z.got!=0;

这会产生如下输出,然后

$(seq 1 99) $(seq 666 667) 50000 $(seq 66419 66456)

您可以将其复制并粘贴到 bash 终端中的 for 循环中,以便为每个 ID 执行命令

for ID in $(seq 1 99) $(seq 666 667) 50000 $(seq 66419 66456); do
  echo $ID
  # Fill the gaps
done

。这与上面的内容相同,只是它既可读又可执行。通过更改上面的“CONCAT”命令,可以生成其他编程语言的语法。或者甚至是 SQL。

This just worked for me to find the gaps in a table with more than 80k rows:

SELECT
  CONCAT(z.expected, IF(z.got-1>z.expected, CONCAT(' thru ',z.got-1), '')) AS missing
FROM (
  SELECT
    @rownum:=@rownum+1 AS expected,
    IF(@rownum=YourCol, 0, @rownum:=YourCol) AS got
  FROM
    (SELECT @rownum:=0) AS a
    JOIN YourTable
    ORDER BY YourCol
  ) AS z
WHERE z.got!=0;

Result:

+------------------+
| missing          |
+------------------+
| 1 thru 99        |
| 666 thru 667     |
| 50000            |
| 66419 thru 66456 |
+------------------+
4 rows in set (0.06 sec)

Note that the order of columns expected and got is critical.

If you know that YourCol doesn't start at 1 and that doesn't matter, you can replace

(SELECT @rownum:=0) AS a

with

(SELECT @rownum:=(SELECT MIN(YourCol)-1 FROM YourTable)) AS a

New result:

+------------------+
| missing          |
+------------------+
| 666 thru 667     |
| 50000            |
| 66419 thru 66456 |
+------------------+
3 rows in set (0.06 sec)

If you need to perform some kind of shell script task on the missing IDs, you can also use this variant in order to directly produce an expression you can iterate over in Bash.

SELECT GROUP_CONCAT(IF(z.got-1>z.expected, CONCAT('$(',z.expected,' ',z.got-1,')'), z.expected) SEPARATOR " ") AS missing
FROM ( SELECT @rownum:=@rownum+1 AS expected, IF(@rownum=height, 0, @rownum:=height) AS got FROM (SELECT @rownum:=0) AS a JOIN block ORDER BY height ) AS z WHERE z.got!=0;

This produces an output like so

$(seq 1 99) $(seq 666 667) 50000 $(seq 66419 66456)

You can then copy and paste it into a for loop in a bash terminal to execute a command for every ID

for ID in $(seq 1 99) $(seq 666 667) 50000 $(seq 66419 66456); do
  echo $ID
  # Fill the gaps
done

It's the same thing as above, only that it's both readable and executable. By changing the "CONCAT" command above, syntax can be generated for other programming languages. Or maybe even SQL.

乱了心跳 2024-10-12 17:20:39

如果您使用 MariaDB 数据库,则可以使用 < 更快 (800%) 的选项a href="https://mariadb.com/kb/en/mariadb/sequence/" rel="nofollow noreferrer">序列存储引擎:

SELECT * FROM seq_1_to_50000 WHERE SEQ NOT IN (SELECT COL FROM TABLE);

If you are using a MariaDB database, you have a faster (800%) option using the sequence storage engine:

SELECT * FROM seq_1_to_50000 WHERE SEQ NOT IN (SELECT COL FROM TABLE);
余生共白头 2024-10-12 17:20:39

一个快速而肮脏的查询应该可以解决这个问题:

SELECT a AS id, b AS next_id, (b - a) -1 AS missing_inbetween
FROM
 (
SELECT a1.id AS a , MIN(a2.id) AS b
FROM arrc_vouchers  AS a1
LEFT JOIN arrc_vouchers AS a2 ON a2.id > a1.id
WHERE a1.id <= 100
GROUP BY a1.id
) AS tab

WHERE
b > a + 1

这将为您提供一个表格,显示上面缺少 idsidnext_id em> 存在,以及之间缺少多少个...例如,

id  next_id  missing_inbetween
 1        4                  2
68       70                  1
75       87                 11

A quick-and-dirty query that should do the trick:

SELECT a AS id, b AS next_id, (b - a) -1 AS missing_inbetween
FROM
 (
SELECT a1.id AS a , MIN(a2.id) AS b
FROM arrc_vouchers  AS a1
LEFT JOIN arrc_vouchers AS a2 ON a2.id > a1.id
WHERE a1.id <= 100
GROUP BY a1.id
) AS tab

WHERE
b > a + 1

This will give you a table showing the id that has ids missing above it, and next_id that exists, and how many are missing between... E.g.,

id  next_id  missing_inbetween
 1        4                  2
68       70                  1
75       87                 11
℉絮湮 2024-10-12 17:20:39

创建一个包含 100 行和一列(包含值 1-100)的临时表。

外部 将此表连接到您的 arrc_vouchers 表,并选择 arrc_vouchers id 为 null 的单列值。

这应该有效:

select tempid from temptable 
left join arrc_vouchers on temptable.tempid = arrc_vouchers.id 
where arrc_vouchers.id is null

Create a temporary table with 100 rows and a single column containing the values 1-100.

Outer Join this table to your arrc_vouchers table and select the single column values where the arrc_vouchers id is null.

This should work:

select tempid from temptable 
left join arrc_vouchers on temptable.tempid = arrc_vouchers.id 
where arrc_vouchers.id is null
你怎么敢 2024-10-12 17:20:39

如果存在一个序列,两个数字之间的间隙最大为 1(例如
1,3,5,6) 那么可以使用的查询是:

select s.id+1 from source1 s where s.id+1 not in(select id from source1) and s.id+1<(select max(id) from source1);
  • table_name - source1
  • column_name - id

If there is a sequence having gap of maximum one between two numbers (like
1,3,5,6) then the query that can be used is:

select s.id+1 from source1 s where s.id+1 not in(select id from source1) and s.id+1<(select max(id) from source1);
  • table_name - source1
  • column_name - id
马蹄踏│碎落叶 2024-10-12 17:20:39

另一种需要查询 + 一些代码执行某些处理的解决方案是:

select l.id lValue, c.id cValue, r.id rValue
  from
  arrc_vouchers l
  right join arrc_vouchers c on l.id=IF(c.id > 0, c.id-1, null)
  left  join arrc_vouchers r on r.id=c.id+1
where 1=1
  and c.id > 0
  and (l.id is null or r.id is null)
order by c.id asc;

请注意,查询不包含任何我们知道 MySQL 规划器无法高效处理的子选择。

这将返回每个centralValue (cValue) 的一个条目,该条目没有较小的值(lValue) 或较大的值(rValue),即:

lValue |cValue|rValue
-------+------+-------
{null} | 2    | 3
8      | 9    | {null}
{null} | 22   | 23
23     | 24   | {null}
{null} | 29   | {null}
{null} | 33   | {null}

无需进一步详细说明(我们将在下一段中看到它们),此输出意味着:

  • 0 到 2 之间没有值
  • 9 到 22 之间没有值
  • 24 到 29 之间没有
  • 值 29 到 33 之间
  • 没有值 33 到 MAX VALUE 之间没有值

所以基本的想法是对同一个表进行 RIGHT 和 LEFT 连接,看看我们是否可以每个值都有相邻值(即,如果中心值为“3”,则我们检查左侧是否有 3-1=2,右侧是否有 3+1),并且当 ROW 在右侧或左侧有 NULL 值时,我们就知道那里没有相邻值。

我的表的完整原始输出是:

select * from arrc_vouchers order by id asc;

0
2
3
4
5
6
7
8
9
22
23
24
29
33

一些注释:

  1. 如果将“id”字段定义为 UNSIGNED,则需要连接条件中的 SQL IF 语句,因此它不允许您将其减少到零以下。如果您保持 c.value > 则这并不是绝对必要的。 0 正如下一个注释中所述,但我将其包含为 doc.
  2. 我正在过滤零中心值,因为我们对任何先前的值都不感兴趣,并且我们可以从下一行导出后值。

An alternative solution that requires a query + some code doing some processing would be:

select l.id lValue, c.id cValue, r.id rValue
  from
  arrc_vouchers l
  right join arrc_vouchers c on l.id=IF(c.id > 0, c.id-1, null)
  left  join arrc_vouchers r on r.id=c.id+1
where 1=1
  and c.id > 0
  and (l.id is null or r.id is null)
order by c.id asc;

Note that the query does not contain any subselect that we know it's not handled performantly by MySQL's planner.

That will return one entry per centralValue (cValue) that does not have a smaller value (lValue) or a greater value (rValue), i.e.:

lValue |cValue|rValue
-------+------+-------
{null} | 2    | 3
8      | 9    | {null}
{null} | 22   | 23
23     | 24   | {null}
{null} | 29   | {null}
{null} | 33   | {null}

Without going into further details (we'll see them in next paragraphs) this output means that:

  • No values between 0 and 2
  • No values between 9 and 22
  • No values between 24 and 29
  • No values between 29 and 33
  • No values between 33 and MAX VALUE

So the basic idea is to do a RIGHT and LEFT joins with the same table seeing if we have adjacents values per value (i.e., if central value is '3' then we check for 3-1=2 at left and 3+1 at right), and when a ROW has a NULL value at RIGHT or LEFT then we know there is no adjacent value.

The complete raw output of my table is:

select * from arrc_vouchers order by id asc;

0
2
3
4
5
6
7
8
9
22
23
24
29
33

Some notes:

  1. The SQL IF statement in the join condition is needed if you define the 'id' field as UNSIGNED, therefore it will not allow you to decrease it under zero. This is not strictly necessary if you keep the c.value > 0 as it's stated in the next note, but I'm including it just as doc.
  2. I'm filtering the zero central value as we are not interested in any previous value and we can derive the post value from the next row.
自由如风 2024-10-12 17:20:39

我尝试了以不同的方式,我发现的最佳性能就是这么简单query:

select a.id+1 gapIni
    ,(select x.id-1 from arrc_vouchers x where x.id>a.id+1 limit 1) gapEnd
    from arrc_vouchers a
    left join arrc_vouchers b on b.id=a.id+1
    where b.id is null
    order by 1
;

... 一个左连接检查下一个id是否存在,只有如果没有找到下一个if,则子查询查找存在的下一个id以找到间隙的末尾。我这样做是因为使用等于 (=) 的查询比大于 (>) 的查询性能更好操作员。

使用 sqlfiddle 与其他查询相比,它没有显示出不同的性能,但是在真实的数据库中,上面的查询结果比其他查询快 3 倍。

架构:

CREATE TABLE arrc_vouchers (id int primary key)
;
INSERT INTO `arrc_vouchers` (`id`) VALUES (1),(4),(5),(7),(8),(9),(10),(11),(15),(16),(17),(18),(19),(20),(21),(22),(23),(24),(25),(26),(27),(28),(29)
;

遵循下面我为比较性能而进行的所有查询:

select a.id+1 gapIni
    ,(select x.id-1 from arrc_vouchers x where x.id>a.id+1 limit 1) gapEnd
    from arrc_vouchers a
    left join arrc_vouchers b on b.id=a.id+1
    where b.id is null
    order by 1
;
select *, (gapEnd-gapIni) qt
    from (
        select id+1 gapIni
        ,(select x.id from arrc_vouchers x where x.id>a.id limit 1) gapEnd
        from arrc_vouchers a
        order by id
    ) a where gapEnd <> gapIni
;
select id+1 gapIni
    ,(select x.id from arrc_vouchers x where x.id>a.id limit 1) gapEnd
    #,coalesce((select id from arrc_vouchers x where x.id=a.id+1),(select x.id from arrc_vouchers x where x.id>a.id limit 1)) gapEnd
    from arrc_vouchers a
    where id+1 <> (select x.id from arrc_vouchers x where x.id>a.id limit 1)
    order by id
;
select id+1 gapIni
    ,coalesce((select id from arrc_vouchers x where x.id=a.id+1),(select x.id from arrc_vouchers x where x.id>a.id limit 1)) gapEnd
    from arrc_vouchers a
    order by id
;
select id+1 gapIni
    ,coalesce((select id from arrc_vouchers x where x.id=a.id+1),concat('*** GAT *** ',(select x.id from arrc_vouchers x where x.id>a.id limit 1))) gapEnd
    from arrc_vouchers a
    order by id
;

您可以使用此 SQL Fiddle

http://sqlfiddle.com/#!9/ 6bdca7/1

I tried it in a different manner, and the best performance that I found was this simple query:

select a.id+1 gapIni
    ,(select x.id-1 from arrc_vouchers x where x.id>a.id+1 limit 1) gapEnd
    from arrc_vouchers a
    left join arrc_vouchers b on b.id=a.id+1
    where b.id is null
    order by 1
;

... one left join to check if the next id exists, only if next if is not found, then the subquery finds the next id that exists to find the end of gap. I did it because the query with equal (=) is better performance than the greater than (>) operator.

Using the sqlfiddle it does not show so a different performance compared to the other queries, but in a real database this query above results in 3 times faster than the others.

The schema:

CREATE TABLE arrc_vouchers (id int primary key)
;
INSERT INTO `arrc_vouchers` (`id`) VALUES (1),(4),(5),(7),(8),(9),(10),(11),(15),(16),(17),(18),(19),(20),(21),(22),(23),(24),(25),(26),(27),(28),(29)
;

Follow below all the queries that I made to compare the performance:

select a.id+1 gapIni
    ,(select x.id-1 from arrc_vouchers x where x.id>a.id+1 limit 1) gapEnd
    from arrc_vouchers a
    left join arrc_vouchers b on b.id=a.id+1
    where b.id is null
    order by 1
;
select *, (gapEnd-gapIni) qt
    from (
        select id+1 gapIni
        ,(select x.id from arrc_vouchers x where x.id>a.id limit 1) gapEnd
        from arrc_vouchers a
        order by id
    ) a where gapEnd <> gapIni
;
select id+1 gapIni
    ,(select x.id from arrc_vouchers x where x.id>a.id limit 1) gapEnd
    #,coalesce((select id from arrc_vouchers x where x.id=a.id+1),(select x.id from arrc_vouchers x where x.id>a.id limit 1)) gapEnd
    from arrc_vouchers a
    where id+1 <> (select x.id from arrc_vouchers x where x.id>a.id limit 1)
    order by id
;
select id+1 gapIni
    ,coalesce((select id from arrc_vouchers x where x.id=a.id+1),(select x.id from arrc_vouchers x where x.id>a.id limit 1)) gapEnd
    from arrc_vouchers a
    order by id
;
select id+1 gapIni
    ,coalesce((select id from arrc_vouchers x where x.id=a.id+1),concat('*** GAT *** ',(select x.id from arrc_vouchers x where x.id>a.id limit 1))) gapEnd
    from arrc_vouchers a
    order by id
;

You can see and test my query using this SQL Fiddle:

http://sqlfiddle.com/#!9/6bdca7/1

剑心龙吟 2024-10-12 17:20:39

它可能不相关,但我一直在寻找类似的东西来列出数字序列中的间隙,并发现这篇文章有多种不同的解决方案,具体取决于您正在寻找的内容。我正在寻找序列中的第一个可用间隙(即下一个可用数字),这似乎工作正常。

SELECT MIN(l.number_sequence + 1) as nextavabile
from patients as l
LEFT OUTER JOIN patients as r on l.number_sequence + 1 = r.number_sequence
WHERE r.number_sequence is NULL

从 2005 年开始,那里讨论了其他几个场景和解决方案!

如何查找使用 SQL 的序列中缺少值

It is probably not relevant, but I was looking for something like this to list the gaps in a sequence of numbers and found this post that has multiple different solutions depending upon exactly what you are looking for. I was looking for the first available gap in the sequence (i.e., next available number), and this seems to work fine.

SELECT MIN(l.number_sequence + 1) as nextavabile
from patients as l
LEFT OUTER JOIN patients as r on l.number_sequence + 1 = r.number_sequence
WHERE r.number_sequence is NULL

Several other scenarios and solutions discussed there, from 2005!

How to Find Missing Values in a Sequence With SQL

雅心素梦 2024-10-12 17:20:39

一个简单但有效的解决方案来查找丢失的自动增量值:

SELECT `id`+1
FROM `table_name`
WHERE `id`+1 NOT IN (SELECT id FROM table_name)

A simple, yet effective, solution to find the missing auto-increment values:

SELECT `id`+1
FROM `table_name`
WHERE `id`+1 NOT IN (SELECT id FROM table_name)
一口甜 2024-10-12 17:20:39

虽然这些看起来都有效,但是当有 50,000 条记录时,结果集返回的时间非常长。

我使用了这个,它找到了间隙或下一个可用的(上次使用的 + 1),并且从查询中返回的速度要快得多。

SELECT a.id as beforegap, a.id+1 as avail
FROM table_name a
where (select b.id from table_name b where b.id=a.id+1) is null
limit 1;

Although these all seem to work, the result set returns in a very lengthy time when there are 50,000 records.

I used this, and it find the gap or the next available (last used + 1) with a much faster return from the query.

SELECT a.id as beforegap, a.id+1 as avail
FROM table_name a
where (select b.id from table_name b where b.id=a.id+1) is null
limit 1;
糖果控 2024-10-12 17:20:39

基于马特给出的答案,此存储过程允许您指定要测试以查找非连续记录的表和列名称 - 从而回答原始问题并演示如何使用 @var 来表示表和/或列存储过程。

create definer=`root`@`localhost` procedure `spfindnoncontiguous`(in `param_tbl` varchar(64), in `param_col` varchar(64))
language sql
not deterministic
contains sql
sql security definer
comment ''
begin
declare strsql varchar(1000);
declare tbl varchar(64);
declare col varchar(64);

set @tbl=cast(param_tbl as char character set utf8);
set @col=cast(param_col as char character set utf8);

set @strsql=concat("select
    ( t1.",@col," + 1 ) as starts_at,
  ( select min(t3.",@col,") -1 from ",@tbl," t3 where t3.",@col," > t1.",@col," ) as ends_at
    from ",@tbl," t1
        where not exists ( select t2.",@col," from ",@tbl," t2 where t2.",@col," = t1.",@col," + 1 )
        having ends_at is not null");

prepare stmt from @strsql;
execute stmt;
deallocate prepare stmt;
end

Based on the answer given by matt, this stored procedure allows you to specify the table and column names that you wish to test to find non-contiguous records - thus answering the original question and also demonstrating how one could use @var to represent tables &/or columns in a stored procedure.

create definer=`root`@`localhost` procedure `spfindnoncontiguous`(in `param_tbl` varchar(64), in `param_col` varchar(64))
language sql
not deterministic
contains sql
sql security definer
comment ''
begin
declare strsql varchar(1000);
declare tbl varchar(64);
declare col varchar(64);

set @tbl=cast(param_tbl as char character set utf8);
set @col=cast(param_col as char character set utf8);

set @strsql=concat("select
    ( t1.",@col," + 1 ) as starts_at,
  ( select min(t3.",@col,") -1 from ",@tbl," t3 where t3.",@col," > t1.",@col," ) as ends_at
    from ",@tbl," t1
        where not exists ( select t2.",@col," from ",@tbl," t2 where t2.",@col," = t1.",@col," + 1 )
        having ends_at is not null");

prepare stmt from @strsql;
execute stmt;
deallocate prepare stmt;
end
_畞蕅 2024-10-12 17:20:39

另一个简单的答案可以找出差距。我们执行仅选择奇数的查询,然后将其右连接到包含所有偶数的查询。只要你没有丢失 id 1;这应该会给你一个完整的列表,说明差距从哪里开始。

您仍然需要查看数据库中的该位置来找出差距有多少个数字。我发现这种方法比建议的解决方案更容易,并且更容易根据独特的情况进行定制。

SELECT *
FROM (SELECT * FROM MyTABLE WHERE MYFIELD % 2 > 0) AS A
RIGHT JOIN FROM (SELECT * FROM MyTABLE WHERE MYFIELD % 2 = 0) AS B
ON A.MYFIELD=(B.MYFIELD+1)
WHERE a.id IS NULL;

Another simple answer that identifies the gaps. We do a query selecting just the odd numbers and we right join it to a query with all the even numbers. As long as you're not missing id 1; this should give you a comprehensive list of where the gaps start.

You'll still have to take a look at that place in the database to figure out how many numbers the gap is. I found this way easier than the solution proposed and much easier to customize to unique situations.

SELECT *
FROM (SELECT * FROM MyTABLE WHERE MYFIELD % 2 > 0) AS A
RIGHT JOIN FROM (SELECT * FROM MyTABLE WHERE MYFIELD % 2 = 0) AS B
ON A.MYFIELD=(B.MYFIELD+1)
WHERE a.id IS NULL;
我的奇迹 2024-10-12 17:20:39

这对我有用:

SELECT distinct(l.membership_no + 1) as nextavabile
from Tablename as l
LEFT OUTER JOIN Tablename as r on l.membership_no + 1 = r.membership_no
WHERE r.membership_no is NULL and l.membership_no is not null order by nextavabile asc;

This works for me:

SELECT distinct(l.membership_no + 1) as nextavabile
from Tablename as l
LEFT OUTER JOIN Tablename as r on l.membership_no + 1 = r.membership_no
WHERE r.membership_no is NULL and l.membership_no is not null order by nextavabile asc;
甲如呢乙后呢 2024-10-12 17:20:39

用户933161发布的评论,

select l.id + 1 as start from sequence as l inner join sequence as r on l.id + 1 = r.id where r.id is null;

更好的是它不会对记录列表的末尾产生误报。 (我不确定为什么这么多人使用左外连接。)
另外,

insert into sequence (id) values (#);

如果 # 是间隙的起始值,则将填充该起始值。 (如果某些字段不能为空,则必须添加具有虚拟值的字段。)

您可以交替查询起始值和填充每个起始值,直到起始值查询返回空集。

当然,只有当您使用足够小的数据集并且手动迭代是合理的时,这种方法才有用。我对 phpMyAdmin 这样的事情了解不够,无法想出自动化更大的方法设置有更多更大的间隙。

Starting from the comment posted by user933161,

select l.id + 1 as start from sequence as l inner join sequence as r on l.id + 1 = r.id where r.id is null;

is better in that it will not produce a false positive for the end of the list of records. (I'm not sure why so many are using left outer joins.)
Also,

insert into sequence (id) values (#);

where # is the start value for a gap will fill that start value. (If there are fields that cannot be null, you will have to add those with dummy values.)

You could alternate between querying for start values and filling in each start value until the query for start values returns an empty set.

Of course, this approach would only be helpful if you're working with a small enough data set that manually iterating like that is reasonable. I don't know enough about things like phpMyAdmin to come up with ways to automate it for larger sets with more and larger gaps.

秋意浓 2024-10-12 17:20:39
CREATE TABLE arrc_vouchers (id int primary key);
INSERT INTO `arrc_vouchers` (`id`) VALUES (1),(4),(5),(7),(8),(9),(10),(11),(15),(16);

WITH RECURSIVE odd_num_cte (id) AS  
(  
    SELECT (select min(id) from arrc_vouchers)   
    union all  
    SELECT id+1 from odd_num_cte where id <(SELECT max(id) from arrc_vouchers)   
)  
SELECT cte.id 
from arrc_vouchers ar right outer join odd_num_cte cte on ar.id=cte.id
where ar.id is null;
CREATE TABLE arrc_vouchers (id int primary key);
INSERT INTO `arrc_vouchers` (`id`) VALUES (1),(4),(5),(7),(8),(9),(10),(11),(15),(16);

WITH RECURSIVE odd_num_cte (id) AS  
(  
    SELECT (select min(id) from arrc_vouchers)   
    union all  
    SELECT id+1 from odd_num_cte where id <(SELECT max(id) from arrc_vouchers)   
)  
SELECT cte.id 
from arrc_vouchers ar right outer join odd_num_cte cte on ar.id=cte.id
where ar.id is null;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文