番号のリストを含むテーブルがあります。表から欠落している数値を見つけるにはどうすればよいですか?
例えば:
numbers id
1 1
5 2
3 3
6 4
7 5
8 6
9 7
20 8
....
不足している番号を見つけるにはどうすればよいですか? 4
のように、9
と20
の間に数字はありません。
私は何も試していませんが、知りたいです。
あなたがコメントしたような現在の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);
_
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
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)
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)
MariaDBの場合、これは次のようなものです。
SELECT seq
FROM seq_1_to_20
LEFT JOIN tbl AS t ON t.numbers = seq
WHERE t.numbers IS NULL