Ciekawe zachowanie się funkcji CHECKSUM pokazał mi wczoraj jeden ze znajomych. Otóż CHECKSUM(10.00) = CHECKSUM(100.00). Zaobserwował On taki zachowanie gdy sprawdzał jakie rekordy zmieniły się w tabelce, a zmiana polegała na zwiększeniu ceny 10-krotnie. Korzystając z funkcji CHECKSUM okazało się, że nic się nie zmieniło. Przykład poniżej :
DECLARE @T1 TABLE ( ID INT, NAZWA VARCHAR(50), CENA DECIMAL(10,2) ); DECLARE @T2 TABLE ( ID INT, NAZWA VARCHAR(50), CENA DECIMAL(10,2) ); INSERT INTO @T1 (ID, NAZWA, CENA) VALUES (1, 'TEST1', 125.23) , (2, 'TEST2', 10.00) , (3, 'TEST3', 23.23); INSERT INTO @T2 (ID, NAZWA, CENA) VALUES (1, 'TEST1', 125.23) , (2, 'TEST2', 10.00) , (3, 'TEST3', 23.23); -- DANE W OBU TABELKACH SĄ IDENTYCZNE SELECT * FROM @T1 SELECT * FROM @T2 -- SPRAWDZENIE CZY SĄ JAKIEŚ REKORDY, KTÓRE SIĘ RÓŻNIĄ SELECT * FROM @T1 AS T1 INNER JOIN @T2 AS T2 ON T1.ID = T2.ID WHERE CHECKSUM(T1.NAZWA, T1.CENA) <> CHECKSUM(T2.NAZWA, T2.CENA) -- ZWIĘKSZENIE CENY W TABELI @T1 UPDATE @T1 SET CENA = CENA * 10 -- DANE W TABELACH RÓŻNIĄ SIĘ SELECT * FROM @T1 SELECT * FROM @T2 -- SPRAWDZENIE CZY REKORDY RÓŻNIĄ SIĘ ZA POMOCĄ CHECKSUM DAJE WYNIK NEGATYWNY -- WEDŁUG CHECKSUM NIC SIĘ NIE ZMIENIŁO SELECT * FROM @T1 AS T1 INNER JOIN @T2 AS T2 ON T1.ID = T2.ID WHERE CHECKSUM(T1.NAZWA, T1.CENA) <> CHECKSUM(T2.NAZWA, T2.CENA) -- OBIE SUMY KONTROLNE SĄ TAKIE SAME SELECT CHECKSUM(T1.NAZWA, T1.CENA) AS CHECKSUM_T1 , CHECKSUM(T2.NAZWA, T2.CENA) AS CHECKSUM_T2 FROM @T1 AS T1 INNER JOIN @T2 AS T2 ON T1.ID = T2.ID
W helpie do funkcji CHECKSUM jest fajne stwierdzenie, które może tłumaczyć takie zachowanie :
However, there is a small chance that the checksum will not change. For this reason, we do not recommend using CHECKSUM to detect whether values have changed, unless your application can tolerate occasionally missing a change.Jak poczytałem na necie to problem jest znany. Jedni piszą swoje funkcje sprawdzające sumę kontrolną np. w C# i podłączają je jako CLR. Inni korzystają z funkcji HashBytes, ale tu elementem wejściowym musi być tekst.
Do powyższej sytuacji rozwiązaniem wydaje się "skastowanie" wartości numerycznej na VARCHARa. Wówczas osiągamy to o co nam chodziło.
A może jest inny sposób ...?