Saya punya sekitar satu miliar baris data dalam sebuah tabel dengan nama dan bilangan bulat dalam kisaran 1-288. Untuk nama yang diberikan , setiap int adalah unik, dan tidak setiap bilangan bulat yang mungkin ada dalam jajaran - jadi ada celah.
Kueri ini menghasilkan contoh kasus:
--what I have:
SELECT *
FROM ( VALUES ('foo', 2),
('foo', 3),
('foo', 4),
('foo', 10),
('foo', 11),
('foo', 13),
('bar', 1),
('bar', 2),
('bar', 3)
) AS baz ("name", "int")
Saya ingin membuat tabel pencarian dengan baris untuk setiap nama dan urutan bilangan bulat yang berdekatan. Setiap baris akan berisi:
nama - nilai awal kolom nama - bilangan bulat pertama di akhir urutan yang berdekatan - nilai akhir dalam rentang urutan yang berdekatan - akhir - mulai + 1
Kueri ini menghasilkan contoh output untuk contoh di atas:
--what I need:
SELECT *
FROM ( VALUES ('foo', 2, 4, 3),
('foo', 10, 11, 2),
('foo', 13, 13, 1),
('bar', 1, 3, 3)
) AS contiguous_ranges ("name", "start", "end", span)
Karena saya memiliki begitu banyak baris, lebih efisien lebih baik. Yang mengatakan, saya hanya perlu menjalankan permintaan ini sekali, jadi itu bukan persyaratan mutlak.
Terima kasih sebelumnya!
Edit:
Saya harus menambahkan bahwa solusi PL / pgSQL dipersilakan (tolong jelaskan Trik Fancy - Saya masih baru untuk PL / pgSQL).
sumber
Jawaban:
Bagaimana kalau menggunakan
with recursive
tampilan tes:
pertanyaan:
hasil:
Saya tertarik untuk mengetahui bagaimana kinerjanya di meja baris miliar Anda.
sumber
Anda dapat melakukannya dengan fungsi windowing. Ide dasarnya adalah menggunakan
lead
danlag
fungsi windowing untuk menarik baris ke depan dan di belakang baris saat ini. Kemudian kita dapat menghitung jika kita memiliki awal atau akhir urutan:(Saya menggunakan tampilan sehingga logikanya akan lebih mudah untuk diikuti di bawah ini.) Jadi sekarang kita tahu apakah barisnya adalah awal atau akhir. Kita harus memecahnya menjadi baris:
Terlihat benar bagi saya :)
sumber
Solusi fungsi jendela lainnya. Tidak tahu tentang efisiensi, saya telah menambahkan rencana eksekusi pada akhirnya (walaupun dengan begitu sedikit baris, mungkin tidak banyak nilainya). Jika Anda ingin bermain-main: SQL-Fiddle test
Tabel dan data:
Pertanyaan:
Rencana Kueri
sumber
Pada SQL Server, saya akan menambahkan satu kolom lagi bernama beforeInt:
Saya akan menggunakan batasan PERIKSA untuk memastikan bahwa beforeInt <int, dan batasan FK (nama, priorInt) merujuk ke (nama, int), dan beberapa kendala lagi untuk memastikan integritas data kedap air. Itu dilakukan, memilih celah itu sepele:
Untuk mempercepatnya, saya dapat membuat indeks yang difilter yang hanya menyertakan celah. Ini berarti bahwa semua celah Anda sudah dikomputasi, jadi pilihannya sangat cepat, dan kendala memastikan integritas data Anda yang sudah dikomputasi. Saya banyak menggunakan solusi seperti itu, semuanya ada di sistem saya.
sumber
Anda dapat mencari Metode Tabibitosan:
Pada dasarnya:
Saya pikir kinerja ini lebih baik:
sumber
rencana kasar:
Ulangi dari 2. hingga tidak ada lagi pembaruan yang terjadi. Dari sana semakin rumit, Gordian, dengan pengelompokan lebih dari maks menit dan minimal maks. Saya kira saya akan memilih bahasa pemrograman.
PS: Tabel sampel yang bagus dengan beberapa nilai sampel akan baik-baik saja, yang bisa digunakan oleh semua orang, jadi tidak semua orang membuat data testdinya dari awal.
sumber
Solusi ini terinspirasi dari jawaban nate c menggunakan fungsi windowing dan klausa OVER. Cukup menarik, jawaban itu kembali ke subqueries dengan referensi eksternal. Dimungkinkan untuk menyelesaikan konsolidasi baris menggunakan level lain dari fungsi windowing. Ini mungkin tidak terlihat terlalu cantik, tapi saya menganggapnya lebih efisien karena menggunakan logika built-in dari fungsi windowing yang kuat.
Saya menyadari dari solusi nate bahwa set awal baris sudah menghasilkan flag yang diperlukan untuk 1) memilih nilai rentang mulai & berakhir DAN 2) untuk menghilangkan baris tambahan di antaranya. Kueri telah membuat subqueries dua mendalam hanya karena keterbatasan fungsi windowing, yang membatasi bagaimana alias kolom dapat digunakan. Secara logis saya bisa menghasilkan hasilnya hanya dengan satu subquery bersarang.
Beberapa catatan lain : Berikut ini adalah kode untuk SQLite3. Dialek SQLite berasal dari postgresql, sehingga sangat mirip dan bahkan dapat bekerja tanpa diubah. Saya menambahkan batasan pembingkaian pada klausa OVER, karena fungsi
lag()
danlead()
hanya perlu satu baris jendela, sebelum dan sesudah masing-masing (sehingga tidak perlu untuk menjaga set default semua baris sebelumnya). Saya juga memilih nama-namafirst
danlast
karena kataend
itu dicadangkan.Hasilnya sama seperti jawaban lainnya, seperti yang diharapkan:
sumber