Mamy bazę danych z tabelą, której wartości zostały zaimportowane z innego systemu. Istnieje kolumna z automatycznym zwiększaniem wartości i nie ma zduplikowanych wartości, ale brakuje wartości. Na przykład, uruchamiając to zapytanie:
select count(id) from arrc_vouchers where id between 1 and 100
powinien zwrócić 100, ale zamiast tego zwraca 87. Czy jest jakieś zapytanie, które mogę uruchomić, które zwróci wartości brakujących liczb? Na przykład rekordy mogą istnieć dla identyfikatorów 1-70 i 83-100, ale nie ma rekordów o identyfikatorach 71-82. Chcę zwrócić 71, 72, 73 itd.
czy to możliwe?
mysql
sql
gaps-and-islands
EmmyS
źródło
źródło
select l.id + 1 as start from sequence as l left outer join sequence as r on l.id + 1 = r.id where r.id is null;
Odpowiedzi:
Aktualizacja
ConfexianMJS dostarczył znacznie lepszej odpowiedzi pod względem wydajności.
Odpowiedź (nie tak szybka, jak to możliwe)
Oto wersja, która działa na stole o dowolnym rozmiarze (nie tylko na 100 wierszach):
gap_starts_at
- pierwszy identyfikator w bieżącej lucegap_ends_at
- ostatni identyfikator w bieżącej luceźródło
order number
że szukałem luk w nie jest odrębny (tabela przechowuje wiersze zamówienia, więc numer zamówienia, do którego należą, powtarza się dla każdego wiersza). Pierwsze zapytanie: 2812 wierszy w zestawie (1 min 31,09 s) . Zrobiłem kolejną tabelę, wybierając różne numery zamówień. Twoje zapytanie bez moich powtórzeń: zestaw 1009 wierszy (18,04 s)SELECT MIN(id) FROM table
?Pomogło mi to znaleźć luki w tabeli z ponad 80 tys. Wierszy:
Wynik:
Zauważ, że kolejność kolumn
expected
igot
jest krytyczna.Jeśli wiesz, że
YourCol
nie zaczyna się od 1 i to nie ma znaczenia, możesz wymienićz
Nowy wynik:
Jeśli potrzebujesz wykonać jakieś zadanie skryptu powłoki na brakujących identyfikatorach, możesz również użyć tego wariantu, aby bezpośrednio utworzyć wyrażenie, które możesz iterować w bash.
Daje to taki wynik
Następnie możesz skopiować i wkleić go do pętli for w terminalu bash, aby wykonać polecenie dla każdego identyfikatora
Jest to to samo, co powyżej, tyle że jest zarówno czytelne, jak i wykonywalne. Zmieniając powyższe polecenie „CONCAT”, można wygenerować składnię dla innych języków programowania. A może nawet SQL.
źródło
CONVERT( YourCol, UNSIGNED )
da lepsze wyniki, jeśli YourCol nie jest już liczbą całkowitą.SELECT MAX(YourCol) FROM YourTable;
SELECT IF((z.got-IF(z.over>0, z.over, 0)-1)>z.expected, CONCAT(z.expected,' thru ',(z.got-IF(z.over>0, z.over, 0)-1)), z.expected) AS missing FROM ( SELECT @rownum:=@rownum+1 AS expected, @target-@missing AS under, (@missing:=@missing+IF(@rownum=YourCol, 0, YourCol-@rownum))-@target AS over, IF(@rownum=YourCol, 0, @rownum:=YourCol) AS got FROM (SELECT @rownum:=0, @missing:=0, @target:=10) AS a JOIN YourTable ORDER BY YourCol ) AS z WHERE z.got!=0 AND z.under>0;
Szybkie i brudne zapytanie, które powinno załatwić sprawę:
Spowoduje to wyświetlenie tabeli pokazującej identyfikator, który ma brakujące identyfikatory nad nim, oraz następny_id, który istnieje i ile brakuje między ... np.
źródło
Jeśli korzystasz
MariaDB
z szybszej (800%) opcji korzystającej z mechanizmu przechowywania sekwencji :źródło
"SELECT MAX(column) FROM table"
i ustawiając zmienną z wyniku, powiedzmy $ MAX ... następnie można zapisać instrukcję sql"SELECT * FROM seq_1_to_". $MAX ." WHERE seq not in (SELECT column FROM table)"
moja składnia jest oparta na phpSELECT @var:= max FROM ....; select * from .. WHERE seq < @max;
ze zmiennymi MySQL.Utwórz tymczasową tabelę ze 100 wierszami i jedną kolumną zawierającą wartości 1-100.
Outer Dołącz tę tabelę do swojej tabeli arrc_vouchers i wybierz wartości w jednej kolumnie, w których identyfikator arrc_vouchers ma wartość null.
Kodowanie tego ślepego, ale powinno działać.
źródło
Alternatywnym rozwiązaniem, które wymaga zapytania + trochę kodu wykonującego pewne przetwarzanie, byłoby:
Zauważ, że zapytanie nie zawiera żadnej podselekcji, o której wiemy, że nie jest obsługiwana wydajnie przez planner MySQL.
To zwróci jeden wpis na centralValue (cValue), który nie ma mniejszej wartości (lValue) ani większej wartości (rValue), tj .:
Bez wchodzenia w dalsze szczegóły (zobaczymy je w następnych akapitach) ten wynik oznacza, że:
Więc podstawową ideą jest wykonanie łączenia w PRAWO i LEWO z tą samą tabelą, sprawdzając, czy mamy wartości sąsiadujące na wartość (tj .: jeśli wartość środkowa to '3', to sprawdzamy 3-1 = 2 po lewej i 3 + 1 po po prawej), a kiedy ROW ma wartość NULL po prawej lub lewej stronie, wtedy wiemy, że nie ma przyległej wartości.
Kompletne surowe dane wyjściowe mojej tabeli to:
Kilka uwag:
źródło
Jeśli istnieje ciąg z maksymalnie jedną przerwą między dwiema liczbami (np. 1,3,5,6), wówczas zapytanie, które można zastosować, to:
source1
id
źródło
na podstawie odpowiedzi udzielonej powyżej przez Lucka ta procedura składowana pozwala określić nazwy tabel i kolumn, które chcesz przetestować, aby znaleźć nieciągłe rekordy - w ten sposób odpowiadając na oryginalne pytanie, a także demonstrując, jak można użyć @var do reprezentowania tabel & / lub kolumny w procedurze składowanej.
źródło
I próbował go w różny sposób i najlepszej wydajności, które znalazłem było to proste zapytanie:
... jedno lewe sprzężenie, aby sprawdzić, czy następny identyfikator istnieje, tylko jeśli następne, jeśli nie zostanie znalezione, wówczas podzapytanie znajduje następny identyfikator, który istnieje, aby znaleźć koniec przerwy. Zrobiłem to, ponieważ zapytanie z równością (=) ma lepszą wydajność niż operator większy niż (>).
Korzystanie z sqlfiddle nie pokazuje tak różnej wydajności innych zapytań, ale w prawdziwej bazie danych powyższe zapytanie daje 3 razy szybszy wynik niż inne.
Schemat:
Wykonaj poniżej wszystkie zapytania, które wykonałem, aby porównać wydajność:
Może to komuś pomoże i przydatne.
Możesz zobaczyć i przetestować moje zapytanie za pomocą tego sqlfiddle :
http://sqlfiddle.com/#!9/6bdca7/1
źródło
Chociaż wszystko wydaje się działać, zestaw wyników powraca po bardzo długim czasie, gdy jest 50 000 rekordów.
Skorzystałem z tego i znalazłem lukę lub następną dostępną (ostatnio używaną + 1) z dużo szybszym powrotem z zapytania.
źródło
Prawdopodobnie nieistotne, ale szukałem czegoś takiego, aby wymienić luki w sekwencji liczb i znalazłem ten post, który ma wiele różnych rozwiązań w zależności od dokładnie tego, czego szukasz. Szukałem pierwszej dostępnej przerwy w sekwencji (tj. Następnej dostępnej liczby) i wydaje się, że działa dobrze.
SELECT MIN (l.number_sequence + 1) jako nextavabile od pacjentów jako l LEFT OUTER JOIN pacjentów jako r na l.number_sequence + 1 = r.number_sequence WHERE r.number_sequence wynosi NULL. Kilka innych scenariuszy i omówionych tam rozwiązań, od 2005 roku!
Jak znaleźć brakujące wartości w sekwencji za pomocą SQL
źródło