Kami memiliki database dengan tabel yang nilainya diimpor dari sistem lain. Ada kolom kenaikan otomatis, dan tidak ada nilai duplikat, tetapi ada nilai yang hilang. Misalnya, menjalankan kueri ini:
select count(id) from arrc_vouchers where id between 1 and 100
harus mengembalikan 100, tetapi mengembalikan 87 sebagai gantinya. Apakah ada kueri yang dapat saya jalankan yang akan mengembalikan nilai dari angka yang hilang? Misalnya, catatan mungkin ada untuk id 1-70 dan 83-100, tetapi tidak ada catatan dengan id 71-82. Saya ingin mengembalikan 71, 72, 73, dll.
Apakah ini mungkin?
mysql
sql
gaps-and-islands
EmmyS
sumber
sumber
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;
Jawaban:
Memperbarui
ConfexianMJS memberikan jawaban yang jauh lebih baik dalam hal kinerja.
Jawaban (tidak secepat mungkin)
Berikut versi yang berfungsi pada tabel dengan berbagai ukuran (tidak hanya pada 100 baris):
gap_starts_at
- id pertama di celah saat inigap_ends_at
- id terakhir di celah saat inisumber
order number
saya sedang mencari celah di tidak berbeda (tabel menyimpan baris pesanan, jadi nomor pesanan mereka berulang untuk setiap baris). Kueri pertama: 2812 baris dalam set (1 menit 31,09 detik) . Membuat tabel lain dengan memilih nomor pesanan yang berbeda. Kueri Anda tanpa pengulangan saya: 1009 baris dalam set (18,04 detik)SELECT MIN(id) FROM table
?Ini hanya berhasil bagi saya untuk menemukan celah di tabel dengan lebih dari 80 ribu baris:
Hasil:
Perhatikan bahwa urutan kolom
expected
dangot
sangat penting.Jika Anda tahu itu
YourCol
tidak dimulai dari 1 dan itu tidak masalah, Anda dapat menggantinyadengan
Hasil baru:
Jika Anda perlu melakukan beberapa jenis tugas skrip shell pada ID yang hilang, Anda juga dapat menggunakan varian ini untuk secara langsung menghasilkan ekspresi yang dapat Anda iterasi di bash.
Ini menghasilkan keluaran seperti itu
Anda kemudian dapat menyalin dan menempelkannya ke loop for di terminal bash untuk menjalankan perintah untuk setiap ID
Ini sama seperti di atas, hanya saja itu dapat dibaca dan dieksekusi. Dengan mengubah perintah "CONCAT" di atas, sintaks dapat dibuat untuk bahasa pemrograman lain. Atau bahkan mungkin SQL.
sumber
CONVERT( YourCol, UNSIGNED )
akan memberikan hasil yang lebih baik jika YourCol belum menjadi integer.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;
Kueri Cepat dan Kotor yang seharusnya melakukan trik:
Ini akan memberi Anda tabel yang menunjukkan id dengan id yang hilang di atasnya, dan next_id yang ada, dan berapa banyak yang hilang di antara ... mis.
sumber
Jika Anda menggunakan,
MariaDB
Anda memiliki opsi yang lebih cepat (800%) menggunakan mesin penyimpanan urutan :sumber
"SELECT MAX(column) FROM table"
dan mengatur variabel dari hasil katakanlah $ MAX ... pernyataan sql kemudian dapat ditulis"SELECT * FROM seq_1_to_". $MAX ." WHERE seq not in (SELECT column FROM table)"
sintaks saya berbasis phpSELECT @var:= max FROM ....; select * from .. WHERE seq < @max;
variabel MySQL.Buat tabel sementara dengan 100 baris dan satu kolom berisi nilai 1-100.
Luar Gabungkan tabel ini ke tabel arrc_vouchers Anda dan pilih nilai kolom tunggal di mana id arrc_vouchers adalah null.
Coding ini buta, tetapi harus bekerja.
sumber
Solusi alternatif yang memerlukan kueri + beberapa kode yang melakukan beberapa pemrosesan adalah:
Perhatikan bahwa kueri tidak berisi subpilihan yang kita tahu tidak ditangani secara baik oleh perencana MySQL.
Itu akan mengembalikan satu entri per centralValue (cValue) yang tidak memiliki nilai lebih kecil (lValue) atau nilai lebih besar (rValue), yaitu:
Tanpa menjelaskan lebih lanjut (kita akan melihatnya di paragraf berikutnya) output ini berarti:
Jadi ide dasarnya adalah melakukan gabungan KANAN dan KIRI dengan tabel yang sama melihat apakah kita memiliki nilai adjacents per nilai (yaitu: jika nilai pusat adalah '3' maka kita periksa 3-1 = 2 di kiri dan 3 + 1 di kanan), dan ketika ROW memiliki nilai NULL di RIGHT atau LEFT maka kita tahu tidak ada nilai yang berdekatan.
Output mentah lengkap dari tabel saya adalah:
Beberapa catatan:
sumber
Jika ada urutan yang memiliki gap maksimal satu antara dua angka (seperti 1,3,5,6) maka query yang dapat digunakan adalah:
source1
id
sumber
berdasarkan jawaban yang diberikan di atas oleh Lucek, prosedur tersimpan ini memungkinkan Anda menentukan nama tabel dan kolom yang ingin Anda uji untuk menemukan rekaman yang tidak bersebelahan - dengan demikian menjawab pertanyaan asli dan juga mendemonstrasikan bagaimana seseorang dapat menggunakan @var untuk merepresentasikan tabel & / atau kolom dalam prosedur tersimpan.
sumber
Saya mencobanya dengan cara yang berbeda dan kinerja terbaik yang saya temukan adalah kueri sederhana ini:
... satu left join untuk memeriksa apakah id berikutnya ada, hanya jika next jika tidak ditemukan, maka subquery mencari id berikutnya yang ada untuk mencari akhir celah. Saya melakukannya karena query dengan equal (=) adalah kinerja yang lebih baik daripada operator (>).
Menggunakan sqlfiddle itu tidak menunjukkan kinerja yang sangat berbeda dari kueri lain tetapi dalam database nyata, kueri di atas ini menghasilkan 3 kali lebih cepat daripada yang lain.
Skema:
Ikuti di bawah semua kueri yang saya buat untuk membandingkan kinerja:
Mungkin itu membantu seseorang dan bermanfaat.
Anda dapat melihat dan menguji kueri saya menggunakan sqlfiddle ini :
http://sqlfiddle.com/#!9/6bdca7/1
sumber
Meskipun ini semua tampaknya berhasil, set hasil kembali dalam waktu yang sangat lama ketika ada 50.000 rekaman.
Saya menggunakan ini, dan menemukan celah atau berikutnya yang tersedia (terakhir digunakan + 1) dengan pengembalian yang jauh lebih cepat dari kueri.
sumber
Mungkin tidak relevan, tetapi saya sedang mencari sesuatu seperti ini untuk membuat daftar celah dalam urutan angka dan menemukan posting ini, yang memiliki beberapa solusi berbeda tergantung pada apa yang Anda cari. Saya sedang mencari celah pertama yang tersedia dalam urutan (yaitu nomor berikutnya yang tersedia), dan ini tampaknya berfungsi dengan baik.
SELECT MIN (l.number_sequence + 1) sebagai nextavabile dari pasien sebagai l LEFT OUTER JOIN patient as r on l.number_sequence + 1 = r.number_sequence DI MANA r.number_sequence adalah NULL. Beberapa skenario dan solusi lain dibahas di sana, dari tahun 2005!
Bagaimana Menemukan Nilai yang Hilang dalam Urutan Dengan SQL
sumber