Saya ingin memilih ke dalam 4 kelompok data dari sebuah tabel yang memiliki jumlah nilai dalam kelompok yang terdistribusi secara merata. Saya yakin bahwa saya tidak menjelaskannya dengan cukup jelas sehingga saya akan mencoba memberikan contoh.
Di sini saya menggunakan NTILE (4) untuk membuat 4 grup:
SELECT Time, NTILE(4) OVER (ORDER BY Time DESC) AS N FROM TableX
Time - N
-------------
10 - 1
9 - 2
8 - 3
7 - 4
6 - 1
5 - 2
4 - 3
3 - 4
2 - 1
1 - 2
Dalam kueri dan hasil di atas, kolom lainnya telah dihilangkan karena singkatnya.
Jadi Anda dapat melihat grup juga sebagai berikut:
1 2 3 4
--- --- --- ---
10 9 8 7
6 5 4 3
2 1
--- --- --- ---
18 15 12 10 Sum Totals of Time
Perhatikan bahwa Jumlah Total Waktu menggunakan NTile tidak benar-benar seimbang antara kelompok. Distribusi nilai Waktu yang lebih baik misalnya:
1 2 3 4
--- --- --- ---
10 9 8 7
3 5 4 6
1 2
--- --- --- ---
14 14 14 13 Sum Totals of Time
Di sini Jumlah Total Waktu lebih merata di 4 kelompok.
Bagaimana saya bisa melakukan ini melalui pernyataan TSQL?
Selanjutnya saya harus mengatakan bahwa saya menggunakan SQL Server 2012. Jika Anda memiliki sesuatu yang dapat membantu saya, beri tahu saya.
Semoga hari Anda menyenangkan.
Stan
sumber
Jawaban:
Berikut adalah bacokan pada suatu algoritma. Itu tidak sempurna, dan tergantung pada berapa banyak waktu yang ingin Anda habiskan untuk memurnikannya, mungkin ada beberapa keuntungan kecil yang akan dibuat.
Anggap Anda memiliki daftar tugas yang harus dilakukan oleh empat antrian. Anda tahu jumlah pekerjaan yang terkait dengan melakukan setiap tugas, dan Anda ingin keempat antrian mendapatkan jumlah pekerjaan yang hampir sama, sehingga semua antrian akan selesai pada waktu yang sama.
Pertama, saya akan mempartisi tugas menggunakan modulous, dipesan berdasarkan ukurannya, dari kecil ke besar.
The
ROW_NUMBER()
pesanan setiap baris dengan ukuran, kemudian memberikan nomor baris, mulai dari 1. nomor baris ini diberikan sebuah "kelompok" (thegrp
kolom) secara round-robin. Baris pertama adalah grup 1, baris kedua adalah grup 2, lalu 3, keempat mendapat grup 0, dan seterusnya.Untuk kemudahan penggunaan, saya menyimpan
time
dangrp
kolom dalam variabel tabel bernama@work
.Sekarang, kita dapat melakukan beberapa perhitungan pada data ini:
Kolom
_grpoffset
adalah jumlah totaltime
pergrp
berbeda dari rata-rata "ideal". Jika totaltime
semua tugas adalah 1000 dan ada empat kelompok, idealnya ada total 250 dalam setiap kelompok. Jika grup berisi total 268, grup itu_grpoffset=18
.Idenya adalah untuk mengidentifikasi dua baris terbaik, satu di kelompok "positif" (dengan terlalu banyak pekerjaan) dan satu di kelompok "negatif" (dengan terlalu sedikit pekerjaan). Jika kita dapat bertukar grup pada dua baris itu, kita dapat mengurangi absolut
_grpoffset
kedua grup.Contoh:
Dengan total total 727, setiap kelompok harus memiliki skor sekitar 182 untuk distribusinya menjadi sempurna. Perbedaan antara skor grup dan 182 adalah apa yang kami tempatkan di
_grpoffset
kolom.Seperti yang Anda lihat sekarang, di dunia terbaik, kita harus memindahkan sekitar 40 poin nilai baris dari grup 1 ke grup 2 dan sekitar 24 poin dari grup 3 ke grup 0.
Berikut kode untuk mengidentifikasi baris kandidat tersebut:
Saya menggabungkan diri dengan ekspresi tabel umum yang kami buat sebelumnya,:
cte
Di satu sisi, grup dengan positif_grpoffset
, di sisi lain grup dengan yang negatif. Untuk lebih lanjut menyaring baris mana yang seharusnya cocok satu sama lain, swap dari baris sisi positif dan negatif harus ditingkatkan_grpoffset
, yaitu membuatnya lebih dekat ke 0.The
TOP 1
danORDER BY
memilih "terbaik" pertandingan swap pertama.Sekarang, yang perlu kita lakukan hanyalah menambahkan
UPDATE
, dan memutarnya sampai tidak ada lagi optimasi yang ditemukan.TL; DR - inilah pertanyaannya
Berikut kode lengkapnya:
sumber