web-dev-qa-db-ja.com

不足している番号を見つける方法は?

番号のリストを含むテーブルがあります。表から欠落している数値を見つけるにはどうすればよいですか?

例えば:

numbers   id
 1         1
 5         2
 3         3
 6         4
 7         5
 8         6
 9         7
 20        8
 ....

不足している番号を見つけるにはどうすればよいですか? 4のように、920の間に数字はありません。

私は何も試していませんが、知りたいです。

2
john.li

あなたがコメントしたような現在のPostgres9.5インストールで、テーブルの既存の最小IDと最大IDの間のすべての不足している整数を必要とすると仮定します(または少なくとも9.3 ):

@ Seb3Wはすでに提案されているgenerate_series() です。ただし、singleクエリで最小値と最大値を取得する方が効率的です。 FROMリストの代わりにSELECTリストでは、_ set-returning-functions のようにgenerate_series()を使用することもできます(標準SQLに準拠し、エラーが発生しにくい)。

_SELECT id
FROM  (SELECT min(id) AS a, max(id) AS z FROM numbers) x, generate_series(a, z) id
LEFT   JOIN numbers n1 USING (id)
WHERE  n1.id IS NULL;
_

候補番号の完全なセットを取得したら、一般的な手法を使用して...

LATERAL結合について:


標準SQLを気にせず、performanceの最後の1滴を絞り出したい場合(またはPostgres 9.2またはLATERAL結合なしで古い)あなたcanSELECTリストでgenerate_series()を使用しますが、それでも単一のSELECTにします:

_SELECT id
FROM  (SELECT generate_series(min(id), max(id)) FROM numbers) n(id)
LEFT   JOIN numbers n1 USING (id)
WHERE  n1.id IS NULL;
_

パフォーマンスの後である場合は、もちろん_numbers.id_のインデックスが必要です。

_CREATE INDEX numbers_id_idx ON numbers (id);
_
4

Postgresqlでは、generate_seriesを使用できます。

SELECT
  generate_series FROM GENERATE_SERIES(
    (select min(id) from numbers), (select max(id) from numbers)
  ) 
WHERE
  NOT EXISTS(SELECT id FROM numbers WHERE id = generate_series)

Mysqlでは、自分でセリエを生成する必要があります。 generate serie mysql

2
Seb3W

SQLサーバーでは、システムテーブルmaster..spt_valuesを使用できます。

USE tempdb
GO

create table numbers(id int)
GO

insert into numbers
select 1
insert into numbers
select 1
insert into numbers
select 5
insert into numbers
select 2
insert into numbers
select 3
insert into numbers
select 3
GO

select number from master..spt_values
where type='p' and number <=(select max(id) from numbers)
and number not in (select id from numbers)
1
slade.liu

MSSQLでは、次のことができます。

--create a your table
CREATE TABLE ##seq
(id INT IDENTITY (1,1)
, txt VARCHAR(50))

--Build your dataset
INSERT INTO ##seq
        (  txt )
VALUES  ( 'boy'), ('girl'),('parent'),( 'boy'), ('girl'),('parent'),( 'boy'), ('girl'),('parent'),( 'boy'), ('girl'),('parent'),( 'boy'), ('girl'),('parent'),( 'boy'), ('girl'),('parent')

--remove your sequence ids to demonstrate
DELETE FROM ##seq WHERE id IN (2,5,7,8,9)

--Query your sequence for gaps 
SELECT (t1.id + 1) as gap_starts_at, 
       (SELECT MIN(t3.id) -1 FROM ##seq t3 WHERE t3.id > t1.id) as gap_ends_at
FROM ##seq t1
WHERE NOT EXISTS (SELECT t2.id FROM ##seq t2 WHERE t2.id = t1.id + 1)
0
user4819549

MariaDBの場合、これは次のようなものです。

SELECT seq
    FROM seq_1_to_20
    LEFT JOIN tbl AS t  ON t.numbers = seq
    WHERE t.numbers IS NULL

参照

0
Rick James