Ich möchte die Daten aus einer Tabelle mit der Summe der Werte in den Gruppen so gleichmäßig wie möglich in 4 Gruppen auswählen. Ich bin sicher, dass ich es nicht klar genug erkläre, also werde ich versuchen, ein Beispiel zu geben.
Hier verwende ich NTILE (4), um die 4 Gruppen zu erstellen:
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
In der obigen Abfrage und im obigen Ergebnis wurden die anderen Spalten der Kürze halber weggelassen.
Sie können die Gruppen also auch wie folgt sehen:
1 2 3 4
--- --- --- ---
10 9 8 7
6 5 4 3
2 1
--- --- --- ---
18 15 12 10 Sum Totals of Time
Beachten Sie, dass die Gesamtsumme der Zeit mit NTile nicht wirklich zwischen den Gruppen ausgeglichen ist. Eine bessere Verteilung der Zeitwerte wäre zum Beispiel:
1 2 3 4
--- --- --- ---
10 9 8 7
3 5 4 6
1 2
--- --- --- ---
14 14 14 13 Sum Totals of Time
Hier ist die Gesamtsumme der Zeit gleichmäßiger auf die 4 Gruppen verteilt.
Wie kann ich dies über eine TSQL-Anweisung durchführen?
Außerdem muss ich sagen, dass ich SQL Server 2012 verwende. Wenn Sie etwas haben, das mir helfen kann, lassen Sie es mich wissen.
Ich wünsche Ihnen einen schönen Tag.
Stan
quelle
Antworten:
Hier ist ein Stich in einen Algorithmus. Es ist nicht perfekt und je nachdem, wie viel Zeit Sie damit verbringen möchten, es zu verfeinern, müssen wahrscheinlich einige weitere kleine Gewinne erzielt werden.
Angenommen, Sie haben eine Tabelle mit Aufgaben, die von vier Warteschlangen ausgeführt werden sollen. Sie kennen den Arbeitsaufwand für die Ausführung der einzelnen Aufgaben und möchten, dass alle vier Warteschlangen fast gleich viel Arbeit erledigen, sodass alle Warteschlangen ungefähr zur gleichen Zeit abgeschlossen werden.
Zunächst würde ich die Aufgaben mit einem modularen, nach Größe geordneten, von klein nach groß aufteilen.
Die
ROW_NUMBER()
ordnet jede Zeile nach Größe und weist dann ab 1 eine Zeilennummer zu. Dieser Zeilennummer wirdgrp
im Round-Robin-Verfahren eine "Gruppe" (die Spalte) zugewiesen . Die erste Reihe ist Gruppe 1, die zweite Reihe ist Gruppe 2, dann 3, die vierte erhält Gruppe 0 und so weiter.Zur Vereinfachung der Verwendung speichere ich die Spalten
time
undgrp
in einer Tabellenvariablen namens@work
.Jetzt können wir einige Berechnungen für diese Daten durchführen:
Die Spalte
_grpoffset
gibt an, um wie viel sich die Summetime
progrp
vom "idealen" Durchschnitt unterscheidet. Wenn die Gesamtzahltime
aller Aufgaben 1000 beträgt und es vier Gruppen gibt, sollte es idealerweise insgesamt 250 in jeder Gruppe geben. Wenn eine Gruppe insgesamt 268 enthält, ist diese Gruppe_grpoffset=18
.Die Idee ist, die zwei besten Zeilen zu identifizieren, eine in einer "positiven" Gruppe (mit zu viel Arbeit) und eine in einer "negativen" Gruppe (mit zu wenig Arbeit). Wenn wir Gruppen in diesen beiden Zeilen austauschen können, können wir das Absolut
_grpoffset
beider Gruppen reduzieren .Beispiel:
Mit einer Gesamtsumme von 727 sollte jede Gruppe eine Punktzahl von ungefähr 182 haben, damit die Verteilung perfekt ist. Der Unterschied zwischen der Punktzahl der Gruppe und 182 ist das, was wir in die
_grpoffset
Spalte eintragen.Wie Sie jetzt sehen können, sollten wir in den besten Welten Zeilen im Wert von etwa 40 Punkten von Gruppe 1 zu Gruppe 2 und etwa 24 Punkte von Gruppe 3 zu Gruppe 0 verschieben.
Hier ist der Code zum Identifizieren dieser Kandidatenzeilen:
Ich verbinde mich selbst mit dem allgemeinen Tabellenausdruck, den wir zuvor erstellt haben
cte
: Auf der einen Seite Gruppen mit positiven_grpoffset
, auf der anderen Seite Gruppen mit negativen. Um weiter herauszufiltern, welche Zeilen zueinander passen sollen, muss der Austausch der Zeilen der positiven und negativen Seite verbessert werden_grpoffset
, dh näher an 0 gebracht werden.Das
TOP 1
undORDER BY
wählt das "beste" Match aus, das zuerst getauscht werden soll.Jetzt müssen wir nur noch ein hinzufügen
UPDATE
und es schleifen, bis keine Optimierung mehr zu finden ist.TL; DR - hier ist die Abfrage
Hier ist der vollständige Code:
quelle