Agregirani bitovi
Objavljeno: 19-06-2014 | Autor: Nenad Živković | Kategorija: Funkcije, T-SQL, Trikovi
Ознаке: BIT, Identity, MAX, MIN
0
Ukoliko dobijete ideju da proverite da li u nekoj BIT koloni postoji makar jedna vrednost true ili makar jedna vrednost false, možda će vam prvo pasti na pamet ideja da iskoristite agregatne funkcije MAX() ili MIN() i lako proverite da li su sve vrednosti iste, s obzirom da postoje samo dve moguće vrednosti.
Međutim, ako pokušate da izvršite komandu:
SELECT MAX(UBoji) FROM dbo.CrtaneEpizode;
ubrzo ćete udariti u zid pošto se javlja sledeća greška:
Msg 8117, Level 16, State 1, Line 1
Operand data type bit is invalid for max operator.
Tip podataka bit ne može da se koristi u agregatnim operacijama, bar ne po dizajnu, ali postoji nekoliko rešenja kako se ovo može lako prevazići. Za početak, da odmah pokažemo i naizgled najnezgrapnije rešenje, ali ipak i najefikasnije:
SELECT CASE WHEN EXISTS (SELECT * FROM dbo.CrtaneEpizode WHERE UBoji = 0) THEN 0 ELSE 1 END AS SveEpizodeUBoji;
EXISTS operator prekida izvršavanje odmah kada pronađe traženu vrednost i vraća jednostavno true ili false na postavljeni zahtev postojanja makar jedne vrednosti.
Drugi način bi bio konvertovanje BIT vrednosti u INT, čime omogućavate upotrebu željene MAX funkcije:
SELECT MIN(CAST(UBoji AS INT)) AS SveEpizodeUBoji FROM dbo.CrtaneEpizode;
I za kraj treći i najjednostavniji način je da prosto dodate broj 0 svojoj BIT koloni i time je implicitno pretvarate u INT:
SELECT MIN(UBoji+0) AS SveEpizodeUBoji FROM dbo.CrtaneEpizode;
S obzirom da druga dva upita zahtevaju index scan nad celom tabelom, a prvi se prekida na prvi nađeni rezultat, očigledno da će se pokazati kao performantniji.
Međutim, ukoliko je pored traženja vrednosti potrebno i grupisanje, što je sasvim realna situacija, onda se prvi upit pretvara u još nezgrapniju konstrukciju sa korelacionim podupitom. Druga dva ostaju i dalje prilično jednostavna i po performansama postaju uporedivi sa prvim, a čak bi trebalo da budu i za nijansu bolji.
SELECT CrtacID , CASE WHEN EXISTS (SELECT * FROM dbo.CrtaneEpizode c2 WHERE c2.UBoji = 0 AND c2.CrtacID = c1.CrtacID) THEN 0 ELSE 1 END AS SveEpizodeUBoji FROM dbo.CrtaneEpizode c1 GROUP BY CrtacID; SELECT CrtacID, MIN(CAST(UBoji AS INT)) AS SveEpizodeUBoji FROM dbo.CrtaneEpizode GROUP BY CrtacID; SELECT CrtacID, MIN(UBoji+0) AS SveEpizodeUBoji FROM dbo.CrtaneEpizode GROUP BY CrtacID;
Ukoliko VI imate još neku ideju, napišite u komentarima.