Chciałbym znaleźć pierwszą „lukę” w kolumnie licznika w tabeli SQL. Na przykład, jeśli istnieją wartości 1, 2, 4 i 5, chciałbym się dowiedzieć 3.
Mogę oczywiście uporządkować wartości i przejść przez to ręcznie, ale chciałbym wiedzieć, czy można to zrobić w języku SQL.
Ponadto powinien to być dość standardowy SQL, działający z różnymi DBMS.
sql
gaps-and-islands
Touko
źródło
źródło
LAG(id, 1, null)
funkcji zOVER (ORDER BY id)
klauzulą.Odpowiedzi:
W
MySQL
iPostgreSQL
:W
SQL Server
:W
Oracle
:ANSI
(działa wszędzie, najmniej wydajnie):Systemy wspierające funkcje okien przesuwnych:
źródło
URL
, chociaż myślę, że może być zakodowane QR.[1, 2, 11, 12]
, to by się znalazł tylko3
. Zamiast tego chciałbym znaleźć 3-10 - w zasadzie początek i koniec każdej przerwy. Rozumiem, że być może będę musiał napisać własny skrypt w Pythonie, który wykorzystuje SQL (w moim przypadku MySql), ale byłoby miło, gdyby SQL przybliżył mnie do tego, czego chcę (mam tabelę z 2 milionami wierszy, która ma luki, więc będę musiał pokroić go na mniejsze kawałki i uruchomić na nim trochę SQL). Przypuszczam, że mógłbym uruchomić jedno zapytanie, aby znaleźć początek przerwy, a następnie drugie, aby znaleźć koniec przerwy, a następnie „scalają” dwie sekwencje.NULL
, nie0
, jeśli stół jest pusty. Dotyczy to wszystkich baz danych.Wszystkie Twoje odpowiedzi działają poprawnie, jeśli masz pierwszą wartość id = 1, w przeciwnym razie ta luka nie zostanie wykryta. Na przykład, jeśli wartości identyfikatora tabeli wynoszą 3,4,5, zapytania zwrócą 6.
Zrobiłem coś takiego
źródło
Nie ma na to wyjątkowo standardowego sposobu w języku SQL, ale można to zrobić za pomocą jakiejś formy klauzuli ograniczającej
(MySQL, PostgreSQL)
lub
(SQL Server)
lub
(Wyrocznia)
źródło
Pierwsza rzecz, która przyszła mi do głowy. Nie jestem pewien, czy w ogóle jest to dobry pomysł, ale powinno działać. Załóżmy, że tabela to,
t
a kolumna toc
:Edycja: ten może być szybszy (i krótszy!):
źródło
LEFT OUTER JOING t2
wymagałoby od ciebie posiadaniat2
tabeli, która jest tylko aliasem.Działa to w SQL Server - nie można tego przetestować w innych systemach, ale wydaje się standardowe ...
Możesz również dodać punkt początkowy do klauzuli where ...
Więc jeśli miałbyś 2000, 2001, 2002 i 2005, gdzie 2003 i 2004 nie istniały, zwróci 2003.
źródło
Następujące rozwiązanie:
Numeruje uporządkowane wiersze sekwencyjnie w klauzuli „ with ”, a następnie dwukrotnie wykorzystuje wynik ze sprzężeniem wewnętrznym na numerze wiersza, ale z przesunięciem o 1, aby porównać wiersz poprzedni z wierszem po, wyszukując identyfikatory z przerwą większą niż 1. Więcej niż oczekiwano, ale ma szersze zastosowanie.
Zapytanie wewnętrzne daje:
Zapytanie zewnętrzne daje:
źródło
Sprzężenie wewnętrzne do widoku lub sekwencji, która ma wszystkie możliwe wartości.
Brak stolika? Zrób stół. W tym celu zawsze trzymam fałszywy stolik.
Następnie,
źródło
Dla
PostgreSQL
Przykład wykorzystujący zapytanie rekurencyjne.
Może to być przydatne, jeśli chcesz znaleźć lukę w określonym zakresie (będzie działać, nawet jeśli tabela jest pusta, podczas gdy inne przykłady nie będą)
źródło
Zgaduję że:
źródło
To wyjaśnia wszystko, o czym do tej pory wspomniano. Zawiera 0 jako punkt początkowy, który zostanie przyjęty domyślnie, jeśli nie ma również żadnych wartości. Dodałem również odpowiednie lokalizacje dla innych części klucza wielowartościowego. Zostało to przetestowane tylko na SQL Server.
źródło
Napisałem szybki sposób, jak to zrobić. Nie jestem pewien, czy jest to najbardziej wydajne, ale wykonuje swoje zadanie. Zauważ, że nie mówi ci o luce, ale podaje id przed i po przerwie (pamiętaj, że przerwa może mieć wiele wartości, więc na przykład 1,2,4,7,11 itp.)
Jako przykładu używam sqlite
Jeśli to jest twoja struktura tabeli
a to są twoje wiersze
Pytanie brzmi
https://gist.github.com/wkimeria/7787ffe84d1c54216f1b320996b17b7e
źródło
źródło
Oto standardowe rozwiązanie SQL, które działa na wszystkich serwerach baz danych bez zmian:
Zobacz w akcji;
źródło
Działa również w przypadku pustych tabel lub z wartościami ujemnymi. Właśnie przetestowano w SQL Server 2012
źródło
Jeśli używasz Firebird 3, jest to najbardziej eleganckie i proste:
źródło
źródło
Stwierdzono, że większość podejść działa bardzo, bardzo wolno
Zakładam, że sekwencja zaczyna się od „1”.mysql
. Oto moje rozwiązanie dlamysql < 8.0
. Testowane na rekordach 1M z przerwą pod koniec ~ 1 sekundę do zakończenia. Nie jestem pewien, czy pasuje do innych odmian SQL.źródło
Jeśli Twój licznik zaczyna się od 1 i chcesz wygenerować pierwszą liczbę sekwencji (1), gdy jest pusta, oto poprawiony fragment kodu z pierwszej odpowiedzi ważny dla Oracle:
źródło
źródło
Jeśli liczby w kolumnie są dodatnimi liczbami całkowitymi (zaczynając od 1), oto jak łatwo to rozwiązać. (zakładając, że ID to nazwa Twojej kolumny)
źródło