Zastosowanie funkcji agregującej MIN do pola BIT

82

Chcę napisać następujące zapytanie:

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

Problem w tym, że SQL Server tego nie lubi, gdy chcę obliczyć minimalną wartość pola bitowego , zwraca błąd Operand data type bit is invalid for min operator.

Mogę zastosować następujące obejście:

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

Ale czy jest coś bardziej eleganckiego? (Na przykład może istnieć funkcja agregująca, której nie znam, i która ocenia logikę andwartości bitów w polu).

pyon
źródło
2
@Adam Robinson: Oczywiście,Operand data type bit is invalid for min operator.
Andomar
4
Nie wiem o bardziej eleganckim, ale trochę krótszym. cast(min(SomeBitField+0) as bit)
Mikael Eriksson,
5
@Andomar: Oczywiście, jeśli już znasz problem, tak, ale inne osoby z podobnymi problemami mogą szukać w komunikacie o błędzie , więc takie informacje muszą znajdować się w pytaniu.
Adam Robinson,

Odpowiedzi:

33

Ponieważ istnieją tylko dwie opcje dla BIT, po prostu użyj instrukcji case:

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

Ma to tę zaletę, że:

  • Brak wymuszania skanowania tabeli (indeksy BITpól prawie nigdy nie są używane)
  • Zwarciem dwukrotnie (raz EXISTSi jeszcze raz za CASE)

To trochę więcej kodu do napisania, ale nie powinno to być straszne. Jeśli masz wiele wartości do sprawdzenia, zawsze możesz zamknąć większy zestaw wyników (ze wszystkimi kryteriami JOINi FILTER) w a CTEna początku zapytania, a następnie odwołać się do tego w CASEinstrukcjach.

JNK
źródło
10
Istnieją trzy opcje, bitjeśli dopuszcza wartość null.
Martin Smith
1
Jeśli bitkolumna składała się wyłącznie z NULLwartości, MINpowinna zostać zwrócona NULL.
Martin Smith
8
Muszę być „mniejszym” programistą, ale chciałbym zobaczyć pełny przykład select 1 from ...podzapytania. To nie ma sensu.
Vaccano
2
@Vaccano -SELECT 1 FROM Outertable WHERE bitfield=1
JNK
2
Oryginalne pytanie zawierało jednak GROUP BY. Musisz uwzględnić grupę według kryteriów w GDZIE.
Tmdean
156

Jedna opcja to MIN(SomeBitField+0). Czyta się dobrze, z mniejszym hałasem (co określiłbym jako elegancję).

To powiedziawszy, jest to bardziej hakerskie niż CASEopcja. I nie wiem nic o szybkości / wydajności.

Ben Mosher
źródło
@Ben, wielkie dzięki, to również pomoże mi w zapytaniu SQL.
PatsonLeaner
@Ben, czy masz jakąś dokumentację +0 ?, Próbowałeś jej poszukać, ale nic nie znalazłem, tylko odniesienia :)
Francisco Sevilla
1
@FranciscoSevilla Myślę, że dzieje się tak z powodu niejawnej konwersji pierwszeństwa: docs.microsoft.com/en-us/sql/t-sql/data-types/ ...
Ben Mosher
7

To zapytanie jest najlepszym rozwiązaniem:

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

Po dodaniu BitField + 0 automatycznie zmieni się w int

Israel Margulies
źródło
7
select min(convert(int, somebitfield))

lub jeśli chcesz zachować wynik jako bit

select convert(bit, min(convert(int, somebitfield)))
Vernard Sloggett
źródło
6

Wypróbuj następującą uwagę: Min reprezentuje I funkcję agregującą, Max reprezentuje funkcję agregującą

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

ten sam wynik

Waleed AK
źródło
5

Ten mały fragment kodu zawsze działał ze mną jak urok:

CONVERT(BIT, MIN(CONVERT(INT, BitField))) as BitField
Legion Chaosu
źródło
2

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

Podaj rozmytą wartość logiczną:

  • 1 oznacza, że ​​to wszystko prawda;

  • 0 oznacza, że ​​wszystko jest fałszywe;

  • wartość między] 0..1 [wskazuje częściowe dopasowanie i może stanowić pewien procent prawdy.

user7370003
źródło