Programując w SQL zastanawiasz się może czasami jaki typ wybrać dla zmiennych lub kolumn w tabelach. SQL Server sam podejmuje czasami decyzję o potrzebie wykonania pewnych konwersji i jeżeli pozwolisz mu zadzaiłać wg swoich algorytmów, to możesz dojść do błędów, które są trudne do zdebuggowania. Przedstawię tutaj kilka takich przykładów:
Źle:
DECLARE @smallValue smallintSET @smallValue = 20000 + 20000
SELECT @smallValue
… w wyniku zwraca błąd.
Msg 220, Level 16, State 1, Line 3Arithmetic overflow error for data type smallint, value = 40000.
Dlaczego?
Bo użyłeś typu smallint. Jeśli przewidujesz, że w obliczeniach może wyjść mniej niż -32 758 lub więcej niż 32 767 to lepiej użyj typu INT. Tinyint ma zakres od 0-255, int to już ponad 2 miliardy a bigint ponad 9 trylionów.
Jak poprawić ten przykład. Ot zmienić typ (więcej o typach i związanych z nimi przygodami znajdziesz na Mobilo / mobilo24 tutaj)?
DECLARE @smallValue intSET @smallValue = 20000 + 20000
SELECT @smallValue
Źle:
DECLARE @date DATETIMESET @date = '20110915 23:59:59.999′
SELECT @date
w wyniku zwraca 2011-09-16 00:00:00.000.
Dlaczego? Bo typ DATETIME zapamiętuje datę z dokładnością do 000 lub 004 lub 007 milisekundy. Czas z 999 milisekundami zostanie zaokrąglony do wartości najbardziej zbliżonej w tym przypadku do 000, ale pociąga to za sobą zmiane sekund, minut itd, dając w efekcie datę z kolejnego dnia.
Jak to poprawić? SQL 2008 wprowadza typ DATETIME2, który nie ma już tego problemu, dlatego
DECLARE @date DATETIME2SET @date = '20110915 23:59:59.999′
SELECT @date
zwraca 2011-09-15 23:59:59.9990000
Źle:
SELECT CONVERT(varchar(6),GetDate(),112)
zwraca dzisiaj czyli 16 IX 2011 wartość 201109.
Dlaczego? Format 112 określa, że data ma być skonwertowana do daty z rokiem zapisanym przy użyciu 4 cyfr. czyli 20110916. Skoro jednak konwersja ma być dokonana na napis sześcioznakowy, to dwie ostatnie cyfry zostają obcięte i zostaje 201109.
Jak to poprawić?
SELECT CONVERT(varchar(8),GetDate(),112)działa poprawnie, bo napis mieści się cały.
Źle: SELECT 'Dzisiaj jest '+GetDate()zwraca błąd:
Msg 241, Level 16, State 1, Line 1 Conversion failed when converting date and/or time from character string.Dlaczego?
Bo dla SQL typ datetime jest tyem mocniejszym niż typy znakowe, a podczas łączenia różnych typów SQL serwer podejmuje decyzję o dokonaniu konwersji do mocniejszego typu. Dlatego zamiast intuicyjnej konwersji do napisu, podejmowana jest próba skonwertowania napisu do typu zgodnego z datą.
Jak to poprawić? Trzeba po prostu wyraźnie wskazać jaki rodzaj konwersji ma być wykonany:
SELECT 'Dzisiaj jest '+CONVERT(VARCHAR(10),GetDate(),104)Zwraca Dzisiaj jest 16.09.2011.
Może znasz inne takie przykłady? Pochwal się nimi!