4

MySQLデータベーステーブルにリストされていない最初の番号を取得するSQLはありますか?元:

表:ユーザー

ID  | Name   | Number
------------------------
1   | John   | 1456
2   | Phil   | 345
3   | Jenny  | 345612

この場合、SQLは、番号が1から344、346から1455、および1457から345611の行のリストを返す必要があります。

助言がありますか?多分いくつかの手順で?

4

5 に答える 5

1

@pst の回答が気に入っていますが、別の代替案を提案します。

  1. 割り当てられていない番号の新しいテーブルを作成し、そこに数千行程度を挿入します。

  2. これらの数字の一部をユーザーに提示します。

  3. 番号が使用されている場合は、未割り当て番号テーブルから削除します。

  4. 必要に応じて、割り当てられていない番号を定期的に生成します。

これらの割り当てられていない番号の生成には、@pst によって提案されたランダムな方法を使用できますが、この方法を使用すると、割り当てられていない番号のリストを生成するのにかかる時間の不確実性をバッチ タスクに移すことができます。ユーザーが待っている間のフロントエンド。これは、数値スペースの使用がまばらな場合はおそらく問題にはなりませんが、使用される数値スペースが増えるにつれて、より大きな問題になります。

于 2012-11-20T22:33:39.170 に答える
1

コメントを考えると、私の最初のアプローチは「乱数」プローブを使用することです。このアプローチは、次のことを前提としています。

  1. Number索引付けされています。と
  2. 利用可能な数よりも「大幅に少ない」ユーザーがいます

アプローチ:

  1. Nクライアント上で無作為に (つまり 1 ~ 10) の数字を選択します。
  2. Number IN (ns..)、または;Number = nについてデータベースにクエリを実行します。N=1それから
  3. 番号が利用可能かどうかは、要求されたレコードが見つからないことに基づいて検出できます。

この場合、のサイズN=1は「問題ない」可能性が高く、6 つの空き番号を見つけるには少なくとも 6 つのデータベース要求が必要ですが、実装するのは最も簡単です。大きくNすると、データベースへのトリップ数が減少します。

必ずトランザクションを使用してください。

于 2012-11-20T22:28:53.257 に答える
0
SELECT 'start', 1 AS number FROM tableA
 UNION
SELECT 'min', number - 1 number FROM tableA
 UNION
SELECT 'max', number + 1 number FROM tableA
 ORDER BY number

答えはhttp://www.sqlfiddle.com/#!2/851de/6で確認できます

次に入力するときに、欠落している数値を比較できます。

于 2012-11-20T22:44:19.953 に答える
0

あなたのコメントに基づいて、以下のアプローチがうまくいくかもしれません。特定の質問に実際に答えるわけではありませんが、おそらく要件を満たしています。

私はあなたの要件が変わることはないと仮定します (例えば、ユーザーに 6 つの ID の選択肢を提示するなど)。率直に言って、これは少し変わった要件だと思いますが、興味深い SQL になります。:-)

これが私のアプローチです: 10 個の乱数を生成します。データベースに既に存在するものを除外します。これらの乱数のうち 6 つをユーザーに提示します。ランダムな ID 番号は、連続した ID 番号と比較して、トランザクション性に関して非常に優れた特性を持っているため、アプリが普及した場合、これは非常にうまくスケーリングするはずです。

SELECT
  temp.i
FROM
  (
          SELECT 18 AS i   -- 10 random
    UNION SELECT 42        -- numbers.
    UNION SELECT 88        
    UNION SELECT 191       -- Let's assume
    UNION SELECT 192       -- you generated
    UNION SELECT 193       -- these in the
    UNION SELECT 1000      -- application
    UNION SELECT 123456    -- layer.
    UNION SELECT 1092930
    UNION SELECT 9892919
  ) temp
LEFT JOIN
  mytable ON (temp.i = mytable.i)
WHERE
  mytable.i IS NULL       -- filter out collisions
LIMIT
  6                       -- limit results to 6

SQLポップクイズタイム!!!

  • WHERE mytable.i IS NULL行 " " が衝突をフィルタリングするのはなぜですか? (ヒント: 主キーの場合、どのmytable.iように null になることができますか?)

ここにいくつかのテストデータがあります:

CREATE TABLE mytable (i BIGINT PRIMARY KEY) ;

INSERT INTO mytable VALUES (88), (3), (192), (123456) ;

上記のクエリを実行すると、結果が次のようになります。88、192、および 123456 はフィルターで除外されていることに注意してください。これらはテスト データに対する衝突になるためです。

+---------+
| i       |
+---------+
|      18 |
|      42 |
|     191 |
|     193 |
|    1000 |
| 1092930 |
+---------+

そして、それらの乱数を生成する方法は? おそらく rand() * 9223372036854775807 が機能します。(負の数が必要ないと仮定して!)

于 2012-11-20T22:49:22.520 に答える
0

自動インクリメント列を使用するだけです。データベースは次の番号を自動的に割り当てます。挿入時にそれが何であるかを知る必要さえありません。取得した番号をユーザーに伝えるだけで、選択肢をまったく与えないでください。

于 2012-11-20T22:32:18.273 に答える