6

外部ソースから取得したゲームのさまざまな試合に関する情報を保存するために使用されるデータベースがあります。いくつかの問題が原因で、データベースに時折ギャップ (ID の欠落が 1 つから数百まで) が生じることがあります。不足しているゲームのデータをプログラムに取り込ませたいのですが、最初にそのリストを取得する必要があります。

テーブルの形式は次のとおりです。

id (pk-identity)  |  GameID (int)  |  etc.  |  etc.  

1 から始まる各 GameID に対してループとクエリを実行するプログラムを作成することを考えていましたが、不足している数字を取得するためのより効率的な方法があるはずです。

SQL Server を使用して、不足しているすべての数値を範囲から見つけるための簡単で効率的な方法はありますか?

4

6 に答える 6

7

アイデアは、ギャップがどこから始まるかを見ることです。SQL Server 2012 を使用していると仮定して、関数lag()lead()関数を使用します。次は次を取得しますid

select t.*, lead(id) over (order by id) as nextid
from t;

ギャップがある場合は、nextid <> id+1. を使用してギャップを特徴付けることができるようになりましたwhere

select id+1 as FirstMissingId, nextid - 1 as LastMissingId
from (select t.*, lead(id) over (order by id) as nextid
      from t
     ) t
where nextid <> id+1;

編集:

がなければ、lead()相関サブクエリで同じことを行います。

select id+1 as FirstMissingId, nextid - 1 as LastMissingId
from (select t.*,
             (select top 1 id
              from t t2
              where t2.id > t.id
              order by t2.id
             ) as nextid
      from t
     ) t
where nextid <> id+1;

がテーブルの主キーであると仮定するとid(または単にインデックスがある場合でも)、どちらの方法でも妥当なパフォーマンスが得られるはずです。

于 2013-09-09T13:22:42.560 に答える
1

私は「ギャップと島」のアプローチが好きです。次のようになります。

WITH Islands AS (
    SELECT GameId, GameID - ROW_NUMBER() OVER (ORDER BY GameID) AS [IslandID]
    FROM dbo.yourTable
)
SELECT MIN(GameID), MAX(Game_id)
FROM Islands
GROUP BY IslandID

そのクエリは、連続した範囲のリストを取得します。そこから、(連続する IslandID で) その結果セットを自己結合して、ギャップを取得できます。ただし、IslandID 自体を連続させるには少し作業が必要です。したがって、上記のクエリを拡張します。

WITH 
cte1 AS (
    SELECT GameId, GameId - ROW_NUMBER() OVER (ORDER BY GameId) AS [rn]
    FROM dbo.yourTable
)
, cte2 AS (
    SELECT [rn], MIN(GameId) AS [Start], MAX(GameId) AS [End]
    FROM cte1
    GROUP BY [rn]
)
,Islands AS (
    SELECT ROW_NUMBER() OVER (ORDER BY [rn]) AS IslandId, [Start], [End]
  from cte2
)

SELECT a.[End] + 1 AS [GapStart], b.[Start] - 1 AS [GapEnd]
FROM Islands AS a
LEFT JOIN Islands AS b
    ON a.IslandID + 1 = b.IslandID
于 2013-09-09T16:31:48.890 に答える
1

数表!

CREATE TABLE dbo.numbers (
   number int NOT NULL
)

ALTER TABLE dbo.numbers
ADD
   CONSTRAINT pk_numbers PRIMARY KEY CLUSTERED (number)
     WITH FILLFACTOR = 100
GO

INSERT INTO dbo.numbers (number)
SELECT (a.number * 256) + b.number As number
FROM     (
        SELECT number
        FROM   master..spt_values
        WHERE  type = 'P'
        AND    number <= 255
       ) As a
 CROSS
  JOIN (
        SELECT number
        FROM   master..spt_values
        WHERE  type = 'P'
        AND    number <= 255
       ) As b
GO

OUTER JOIN次に、2 つのテーブル間で or EXISTS`を実行し、ギャップを見つけることができます...

SELECT *
FROM   dbo.numbers
WHERE  NOT EXISTS (
         SELECT *
         FROM   your_table
         WHERE  id = numbers.number
       )

-- OR

SELECT *
FROM   dbo.numbers
 LEFT
  JOIN your_table
    ON your_table.id = numbers.number
WHERE  your_table.id IS NULL
于 2013-09-09T13:22:47.440 に答える
1
     SELECT * FROM #tab1
            id          col1
            ----------- --------------------
            1           a
            2           a
            3           a
            8           a
            9           a
            10          a
            11          a
            15          a
            16          a
            17          a
            18          a

 WITH cte (id,nextId) as
                (SELECT t.id, (SELECT TOP 1 t1.id FROM #tab1 t1 WHERE t1.id > t.id) AS nextId  FROM #tab1 t)

 SELECT id AS 'GapStart', nextId AS 'GapEnd' FROM cte
                WHERE id + 1 <> nextId

    GapStart    GapEnd
    ----------- -----------
    3           8
    11          15
于 2017-03-17T13:01:08.253 に答える
0

これを試してください (これは 1 から始まる最大 10000 個の ID をカバーします。さらに必要な場合は、下の数値表にさらに追加できます):

;WITH Digits AS (
    select Digit 
    from ( values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) as t(Digit))
,Numbers AS (
    select u.Digit 
          + t.Digit*10 
          + h.Digit*100 
          + th.Digit*1000
          + tth.Digit*10000 
          --Add 10000, 100000 multipliers if required here.
          as myId
    from Digits u
    cross join Digits t
    cross join Digits h
    cross join Digits th
    cross join Digits tth
    --Add the cross join for higher numbers 
    )
SELECT myId 
FROM Numbers
WHERE myId NOT IN (SELECT GameId FROM YourTable)
于 2013-09-09T14:02:52.037 に答える