Anwenden der MIN-Aggregatfunktion auf ein BIT-Feld

82

Ich möchte folgende Abfrage schreiben:

SELECT   ..., MIN(SomeBitField), ...
FROM     ...
WHERE    ...
GROUP BY ...

Das Problem ist, SQL Server mag es nicht, wenn ich den Mindestwert eines Bitfeldes berechnen möchte, gibt es den Fehler zurück Operand data type bit is invalid for min operator.

Ich könnte die folgende Problemumgehung verwenden:

SELECT   ..., CAST(MIN(CAST(SomeBitField AS INT)) AS BIT), ...
FROM     ...
WHERE    ...
GROUP BY ...

Aber gibt es etwas eleganteres? (Zum Beispiel könnte es eine Aggregatfunktion geben, die ich nicht kenne und die die Logik andder Bitwerte in einem Feld auswertet .)

pyon
quelle
2
@ Adam Robinson: OffensichtlichOperand data type bit is invalid for min operator.
Andomar
3
Ich weiß nicht, was eleganter ist, aber es ist etwas kürzer. cast(min(SomeBitField+0) as bit)
Mikael Eriksson
5
@Andomar: Wenn Sie das Problem bereits kennen, ja, aber andere mit ähnlichen Problemen suchen möglicherweise nach der Fehlermeldung. Daher müssen solche Informationen in der Frage enthalten sein.
Adam Robinson

Antworten:

33

Da es nur zwei Optionen gibt BIT, verwenden Sie einfach eine case-Anweisung:

SELECT CASE WHEN EXISTS (SELECT 1 FROM ....) THEN 1 ELSE 0 END AS 'MinBit'
FROM ...
WHERE ...

Dies hat den Vorteil von:

  • Kein Tabellenscan erzwingen (Indizes für BITFelder werden so gut wie nie verwendet)
  • ZWEIMAL kurzschließen (einmal für EXISTSund wieder für CASE)

Es ist etwas mehr Code zum Schreiben, aber es sollte nicht schrecklich sein. Wenn Sie mehrere Werte überprüfen müssen, können Sie Ihre größere Ergebnismenge (mit allen JOINund FILTERKriterien) immer in a CTEam Anfang der Abfrage einkapseln und auf diese in den CASEAnweisungen verweisen .

JNK
quelle
10
Es gibt drei Optionen, bitwenn es nullbar ist.
Martin Smith
1
Wenn die bitSpalte vollständig aus NULLWerten bestand, MINsollte zurückgegeben werden NULL.
Martin Smith
8
Ich muss ein "kleinerer" Programmierer sein, aber ich hätte gerne ein vollständiges Beispiel für die select 1 from ...Unterabfrage gesehen. Das macht nicht ganz Sinn.
Vaccano
2
@ Vaccano -SELECT 1 FROM Outertable WHERE bitfield=1
JNK
2
Die ursprüngliche Frage enthielt jedoch eine GROUP BY. Sie müssen die Gruppe nach Kriterien in das WHERE aufnehmen.
Tmdean
155

Eine Option ist MIN(SomeBitField+0). Es liest sich gut, mit weniger Lärm (was ich als Eleganz bezeichnen würde).

Das heißt, es ist mehr hack-ish als die CASEOption. Und ich weiß nichts über Geschwindigkeit / Effizienz.

Ben Mosher
quelle
@ Ben, vielen Dank. Dies hilft mir auch bei meiner SQL-Abfrage.
PatsonLeaner
@ Ben, haben Sie eine Dokumentation von +0 ?, Haben versucht, danach zu suchen, aber nichts gefunden, nur als Referenz :)
Francisco Sevilla
1
@FranciscoSevilla Ich glaube, das liegt an der impliziten Prioritätskonvertierung: docs.microsoft.com/en-us/sql/t-sql/data-types/…
Ben Mosher
7

Diese Abfrage ist die beste Lösung:

SELECT CASE WHEN MIN(BitField+0) = 1 THEN 'True' ELSE 'False' END AS MyColumn
 FROM MyTable

Wenn Sie das BitField + 0 hinzufügen, wird es automatisch wie int

Israel Margulies
quelle
7
select min(convert(int, somebitfield))

oder wenn Sie das Ergebnis als Bit behalten möchten

select convert(bit, min(convert(int, somebitfield)))
Vernard Sloggett
quelle
6

Versuchen Sie Folgendes : Hinweis: Min. Repräsentieren und Aggregatfunktion, Max. Repräsentieren oder Aggregatfunktion

SELECT   ..., MIN(case when SomeBitField=1 then 1 else 0 end), MIN(SomeBitField+0)...
FROM     ...
WHERE    ...
GROUP BY ...

gleiches Ergebnis

Waleed AK
quelle
5

Dieser kleine Code hat bei mir immer wie ein Zauber gewirkt:

CONVERT(BIT, MIN(CONVERT(INT, BitField))) as BitField
Chaos Legion
quelle
2

AVG (CAST (boolean_column AS FLOAT)) OVER (...) AS BOOLEAN_AGGREGATE

Geben Sie einen Fuzzy-Booleschen Wert an:

  • Ich gebe an, dass das alles wahr ist.

  • 0 zeigt an, dass alles falsch ist;

  • Ein Wert zwischen] 0..1 [zeigt eine teilweise Übereinstimmung an und kann ein Prozentsatz der Wahrheit sein.

user7370003
quelle