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.index + a.base より大きくなるように、最初の行 'a' を見つける必要があります。

これは、任意の 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

テーブルに「ベース」の値が複数ある場合、質問の意味がわかりません。たとえば、「上限インデックス値が最​​も近い行」は、「ベース」の値が同じである必要がありますか?

いずれにせよ、関数 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

標準 SQL 以外に依存しない方法の 1 つは、「のすべての可能な値」の別のテーブルを保持することですindex

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

次に、users テーブルが次のようになっているとします。最初のギャップは 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)

LEFT JOINインデックス テーブルでa を使用して、この最初のギャップを見つけることができます。

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)

インデックス テーブルの終了後に最初のギャップが発生した場合、これは失敗します。この場合、エラーを検出してインデックス テーブルを拡張できます。

于 2012-04-23T03:02:01.227 に答える
0

行を削除する代わりに、別の列を追加して使用可能としてマークできますか? 次に、指定されたベースで「AVAILABLE」とマークされているテーブルから 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 に答える