1

假设我有下表:

id  name  base   index
0   A     2      0
1   B     2      2
2   C     2      4
3   D     2      6
4   E     2      8
5   F     2      10

因此,index = base * i,其中 i 是该行在序列中的位置。

有时会删除一些行,例如,如果我删除名为 C 和 D 的行:

id  name  base   index
0   A     2      0
1   B     2      2
4   E     2      8
5   F     2      10

新行总是在最后一行之后添加,因此在这种情况下,下一行将是 MAX(index)+base=12,但是由于删除的行,索引列中的值之间留下的间隙会在一段时间后成为问题。如果不是最后插入而是将其插入第一个可用间隙,则不会发生问题。

所以,我怀疑找到第一个可用间隙的任何查询都会像 MAX(index) 一样有效,但最有效的解决方案是什么?也许已经足够好了。

如果不清楚,我需要找到第一行'a',使得具有最接近上索引值的行大于a.index + a.base。

这适用于对任何 SQL 数据库使用 ORM 的应用程序,因此它必须是严格的标准 SQL。

编辑

这是对真实表和真实问题的简化,我正在寻找仅使用基列和索引列的解决方案。涉及在其他表中添加新列或索引的解决方案对我的应用程序不实用。

编辑 2

似乎基列使它变得更加复杂,但这不是必需的。问题可以简化为如下表:

id  name  index
0   A     0
1   B     1
4   E     4
5   F     5

我需要在哪里找到第一行'a',使得索引最低的行高于a.index + x。在这种情况下 x = 1。

枚举而不先排序或利用 id 不是可靠的解决方案,因为这些可能会改变。例如,如果行也是这样的,则解决方案必须起作用:

id  name  index
0   A     0
23  F     5
45  E     4
90  B     1
4

4 回答 4

1

如果表中有多个“base”值,我不清楚你的问题是什么意思。例如,“具有最接近上索引值的行”是否必须具有相同的“基数”值?

无论如何,如果您使用的是实现函数 LEAD() 的 SQL 平台,这可能是一个开始。您可能需要用适当的方言重新表述 TOP。将 999999999 替换为大于 index+base 的最大可能值的任何值。

with LeadAdded as (
  select 
    lead(index,1,999999999) over (order by index) as nxt,
    *
  from yourTable
)
  select top (1) *
  from LeadAdded
  where nxt > index + base;
  order by index
于 2012-04-23T02:28:43.343 回答
0

您可以添加另一列以将其标记为可用,而不是删除该行?然后,您可以从表中选择具有给定基数的标记为“可用”的 MIN(id)。如果找不到,则插入。这样您就可以避免出现空白,保留历史记录,甚至可以简化?

于 2012-04-23T01:49:20.713 回答
0

大多数 SQL 方言都支持窗口函数,因此您可以执行以下操作:

select min(id)
from 
(
   select t.*, 
      row_number() over (order by id) as rownum
   from t
)
where id <> rownum

这将返回第一个乱序的 id。

我可能会建议,类似于第一个建议。删除一行时,将 id 存储在另一个“可用”id 表中。插入时,请先查看此表。如果没有可用的,则创建一个新的。

于 2012-04-23T02:05:30.073 回答
0

好吧,一种不依赖于标准 SQL 之外的任何东西的方法是保留一个单独的表,其中包含“所有可能的值index”:

SELECT * FROM indices LIMIT 7;
+------+
| idx  |
+------+
|    0 |
|    2 |
|    4 |
|    6 |
|    8 |
|   10 |
|   12 |
+------+
7 rows in set (0.00 sec)

然后假设您的用户表看起来像这样,第一个间隙发生在 index=4 处:

SELECT * FROM users;
+------+------+------+------+
| id   | name | base | idx  |
+------+------+------+------+
|    0 | A    |    2 |    0 |
|    1 | B    |    2 |    2 |
|    4 | E    |    2 |    8 |
|    5 | F    |    2 |   10 |
+------+------+------+------+
4 rows in set (0.00 sec)

您可以将 aLEFT JOIN与索引表一起使用来查找第一个间隙:

SELECT indices.*
FROM indices
LEFT JOIN users
USING(idx)
WHERE users.idx IS NULL
ORDER BY idx
LIMIT 1;

+------+
| idx  |
+------+
|    4 |
+------+
1 row in set (0.00 sec)

This will fail if the first gap occurs after the end of the indices table, in which case you could detect the error and extend the indices table.

于 2012-04-23T03:02:01.227 回答