Wie kann der Mindestwert aus mehreren Spalten am besten ausgewählt werden?
Gegeben, die folgende Tabelle in SQL Server 2005:
ID Col1 Col2 Col3
-- ---- ---- ----
1 3 34 76
2 32 976 24
3 7 235 3
4 245 1 792
Was ist der beste Weg zu schreiben, die Abfrage liefert das folgende Ergebnis (D. H. eine, die Erträge der letzten Spalte eine Spalte mit der minium-Werte aus Col1, Col2, und Col 3 für jede Zeile)?
ID Col1 Col2 Col3 TheMin
-- ---- ---- ---- ------
1 3 34 76 3
2 32 976 24 24
3 7 235 3 3
4 245 1 792 1
UPDATE:
Zur Verdeutlichung (wie ich schon sagte, in den coments) in der realen Szenario die Datenbank ist richtig normalisiert. Diese "array" Spalten nicht in eine tatsächliche Tabelle, aber in einer Ergebnismenge, die erforderlich ist in einem Bericht. Und die neue Anforderung ist, dass der Bericht auch die Bedürfnisse dieser MinValue Spalte. Ich kann es nicht ändern, die zugrunde liegende Ergebnismenge, und deshalb war ich auf der Suche nach T-SQL für ein handliches "get out of jail card".
Habe ich versucht, den FALL Ansatz, die unten erwähnt werden, und es funktioniert, obwohl es ein bisschen umständlich. Es ist auch komplizierter als angegeben in den Antworten, weil Sie brauchen, um zu bieten für die Tatsache, dass es zwei min Werte in der gleichen Zeile.
Sowieso, ich dachte, ich würde post meine aktuelle Lösung, die aufgrund meiner Einschränkungen, die ziemlich gut funktioniert. Es verwendet die UNPIVOT-operator:
with cte (ID, Col1, Col2, Col3)
as
(
select ID, Col1, Col2, Col3
from TestTable
)
select cte.ID, Col1, Col2, Col3, TheMin from cte
join
(
select
ID, min(Amount) as TheMin
from
cte
UNPIVOT (Amount for AmountCol in (Col1, Col2, Col3)) as unpvt
group by ID
) as minValues
on cte.ID = minValues.ID
Ich werde Anfang sagen, dass ich nicht erwarten, dass diese um bieten die beste Leistung, aber angesichts der Umstände (ich kann nicht-redesign-alle Abfragen, die gerade für die neuen MinValue Spalte Anforderung), ist es eine ziemlich elegante "get out of jail card".
InformationsquelleAutor der Frage stucampbell | 2008-12-15
Du musst angemeldet sein, um einen Kommentar abzugeben.
Gibt es wahrscheinlich viele Möglichkeiten, dies zu erreichen. Mein Vorschlag ist, verwenden Sie Fall/Wann es zu tun. Mit 3 Spalten, es ist nicht allzu schlimm.
InformationsquelleAutor der Antwort G Mastros
Mithilfe
CROSS APPLY
:SQL Fiddle
InformationsquelleAutor der Antwort Nizam
Der beste Weg ist eigentlich nicht, es zu tun - es ist merkwürdig, dass Leute, die darauf bestehen, auf die Speicherung Ihrer Daten in einer Weise, erfordert SQL "gymnastik", um sinnvolle Informationen extrahieren kann, wenn es viel einfachere Wege, um das gewünschte Ergebnis erzielen, wenn Sie nur normalisieren das schema korrekt.
Den Recht Weg, dies zu tun, meiner Meinung nach, ist der folgenden Tabelle:
mit
ID/Col
als primary key und möglicherweiseCol
als extra-Taste, je nach Ihren Bedürfnissen. Dann deine Abfrage wird eine einfacheund Sie können noch behandeln die einzelnen 'alten Spalten separat mithilfe
in deinen anderen Abfragen. Dies ermöglicht eine einfache Erweiterung soll die Zahl der "alten Säulen" wachsen.
Macht Sie Ihre Abfragen so viel einfacher. Die Allgemeine Richtlinie, Neige ich dazu, Sie zu verwenden ist, wenn Sie immer etwas, das aussieht wie ein array in eine Datenbank-Zeile, sind Sie wahrscheinlich etwas falsch machen und sollte sich überlegen, die Umstrukturierung der Daten.
Jedoch, wenn aus irgendeinem Grund Sie nicht ändern Sie die Spalten, würde ich vorschlagen, die Verwendung von insert-und update-Triggern und fügen Sie anderen Spalte, die diese Trigger gesetzt, um das minimum auf
Col1/2/3
. Dadurch bewegt sich die 'Kosten' der operation Weg von der wählen Sie die update/insert, wo es hingehört - die meisten Datenbank Tabellen in meiner Erfahrung sind Lesen, weit mehr als oft geschrieben, so dass die Kosten auf schreiben neigt dazu, effizienter zu sein im Laufe der Zeit.In anderen Worten, das minimum für eine Zeile wird nur geändert, wenn eine der anderen Spalten ändern, so das ist, wenn Sie sollten ihn zu berechnen, nicht jedes mal, wenn Sie wählen Sie (, die verschwendet wird, wenn die Daten nicht ändern). Sie würde dann am Ende mit einer Tabelle wie:
Andere Möglichkeit, die Entscheidungen zu treffen, bei
select
Zeit ist in der Regel eine schlechte Idee, performance-Weise, da die Daten nur änderungen auf einfügen/aktualisieren - das hinzufügen einer weiteren Spalte nimmt mehr Platz in der DB und wird etwas langsamer sein, für die inserts und updates, kann aber viel schneller wählt - der bevorzugte Ansatz sollte davon abhängen, Ihre Prioritäten dort, aber, wie gesagt, die meisten Lesen von Tabellen weit mehr als oft sind Sie geschrieben.InformationsquelleAutor der Antwort paxdiablo
Können Sie die "brute-force" Ansatz mit einem twist:
Wenn die erste wenn-Bedingung schlägt fehl, es wird garantiert, dass Col1 nicht den kleinsten Wert, daher können Sie beseitigen es vom rest der Bedingungen. Ebenfalls für die nachfolgende Bedingungen. Für fünf Spalten Ihre Abfrage wird:
Beachten Sie, dass, wenn es einen Gleichstand zwischen zwei oder mehr Spalten dann
<=
sorgt dafür, dass wir die Ausfahrt derCASE
Aussage so früh wie möglich.InformationsquelleAutor der Antwort Salman A
Wenn die Spalten waren ganzen zahlen, wie in Ihrem Beispiel würde ich eine Funktion erstellen:
dann, wenn ich brauche, um es zu verwenden, die ich tun würde :
wenn du 5 Spalten dann die oben genannten wird
InformationsquelleAutor der Antwort Georgios
Könnte man dies auch mit einer union-Abfrage. Als die Anzahl der Spalten erhöhen, müssten Sie die Abfrage ändern, aber zumindest wäre es ein straight forward änderung.
InformationsquelleAutor der Antwort G Mastros
InformationsquelleAutor der Antwort dsz
Dies ist brute-force, arbeitet aber
... denn min() funktioniert nur über eine Spalte und nicht über Spalten.
InformationsquelleAutor der Antwort Learning
Beide diese Frage
Und diese Frage versuchen, diese zu beantworten.
Rückblick ist, dass Oracle verfügt über eine eingebaute Funktion, die mit Sql Server-Sie sind stecken entweder die Definition einer user-defined-Funktion oder mithilfe von case-Anweisungen.
InformationsquelleAutor der Antwort Sam Saffron
Wenn Sie sind in der Lage, eine gespeicherte Prozedur, könnte es ein array von Werten, und Sie könnten einfach anrufen.
InformationsquelleAutor der Antwort Kev
InformationsquelleAutor der Antwort Phil Corcoran
Einem kleinen twist auf die union-Abfrage:
InformationsquelleAutor der Antwort Lamprey
Wenn Sie SQL 2005 können Sie etwas tun, ordentlich wie diese:
Diese Weise Sie don ' T get lost in so vielen Betreibern 🙂
Könnte sich dies jedoch langsamer, als die andere Wahl.
Es ist deine Entscheidung...
InformationsquelleAutor der Antwort leoinfo
Unten verwende ich eine temp-Tabelle zu erhalten, die mindestens mehrere Termine. Der erste temp-Tabelle, mehrere Abfragen zu verknüpften Tabellen um diverse Daten (sowie andere Werte für die Abfrage), die zweite temp-Tabelle bekommt dann die verschiedenen Spalten und die minimale Datum an, wie viele Pässe, wie es das Datum Spalten.
Dies ist im wesentlichen wie die union-Abfrage, die gleiche Anzahl von Durchläufen benötigt, kann aber effizienter sein, basierend auf Erfahrung, aber würde die getestet werden müssen). Effizienz war nicht ein Problem in diesem Fall (8.000 Datensätze). Man könnte index etc.
InformationsquelleAutor der Antwort user3438020
InformationsquelleAutor der Antwort Tino Jose Thannippara
Wenn Sie wissen, was Werte, die Sie suchen, in der Regel ein status-code, die folgenden können hilfreich sein:
InformationsquelleAutor der Antwort Israel Margulies
Verwenden:
InformationsquelleAutor der Antwort user3493139
Mehrere Spalten seiner besten verwenden Sie eine CASE-Anweisung, jedoch für zwei numerische Spalten i und j können Sie einfache Mathematik:
min(i,j) = (i+j)/2 - abs(i-j)/2
Diese Formel kann verwendet werden, um den minimalen Wert von mehreren Spalten, aber es ist wirklich unordentlich, Vergangenheit 2, min(i,j,k) wäre min(i,min(j,k))
InformationsquelleAutor der Antwort user3658750