Kiedy tekst z pliku CSV ma stać się liczbą, a data z formularza poprawną wartością date, samo przechowywanie danych nie wystarczy. W SQL Server funkcja CONVERT pozwala kontrolować takie zmiany, w tym format daty, długość tekstu i sposób obsługi nieprawidłowych wartości. Pokażę składnię, praktyczne przykłady, różnice względem CAST, użycie TRY_CONVERT oraz błędy, które potrafią zepsuć wyniki albo wydajność zapytania.
Najważniejsze zasady konwersji danych w SQL Server
-
CONVERTzmienia typ danych i pozwala dodatkowo określić styl formatowania. - Styl 23, 112 lub 126 jest bezpieczniejszy dla dat niż niejednoznaczne formaty lokalne.
-
TRY_CONVERTzwracaNULL, gdy zmiana typu się nie powiedzie, zamiast przerywać całe zapytanie. - Jawna długość tekstu chroni przed obcięciem wartości podczas konwersji.
- Konwersja kolumny w filtrze może zablokować użycie indeksu i znacząco spowolnić zapytanie.
Czym jest CONVERT i kiedy warto go używać
CONVERT służy do jawnej zmiany typu danych w wyrażeniu. Można na przykład zamienić tekst na liczbę, datę na tekst albo wartość typu datetime na samą datę. Dla mnie najważniejsza zaleta tej funkcji to możliwość określenia stylu konwersji, szczególnie przy pracy z datami.
CONVERT (typ_danych [(długość)], wyrażenie [, styl])Prosty przykład wygląda tak:
SELECT CONVERT(int, '2026') AS Rok,
CONVERT(varchar(10), 12345) AS Numer;W pierwszym przypadku tekst zostaje zamieniony na liczbę całkowitą. W drugim liczba trafia do tekstu, którego maksymalna długość wynosi 10 znaków. Ten pozornie drobny parametr ma znaczenie, bo pominięcie długości dla typów tekstowych może prowadzić do nieoczywistych rezultatów.
CONVERT a CAST
Obie funkcje wykonują konwersję typu, ale mają inną składnię. CAST jest bardziej uniwersalny i czytelny, natomiast CONVERT daje dodatkowy parametr style, który steruje między innymi formatem daty.
| Funkcja | Przykład | Kiedy wybrać |
|---|---|---|
CAST |
CAST(Cena AS decimal(10,2)) |
Gdy potrzebujesz prostej i przenośnej składni. |
CONVERT |
CONVERT(varchar(10), Data, 23) |
Gdy kontrolujesz format daty lub godzinę. |
TRY_CONVERT |
TRY_CONVERT(int, Tekst) |
Gdy dane mogą być niepoprawne i nie chcesz przerwać zapytania. |
W kodzie aplikacji .NET zwykle nie ma sensu używać CONVERT tylko dlatego, że jest bardziej rozbudowany. Jeśli nie potrzebuję stylu, wybieram CAST. Gdy jednak obrabiam daty pochodzące z integracji, raportów lub eksportów, dodatkowy parametr często decyduje o tym, czy wynik będzie jednoznaczny.
Konwersja liczb i tekstu bez nieprzyjemnych niespodzianek
Najczęstszy scenariusz to konwersja wartości tekstowej na typ liczbowy. SQL Server zaakceptuje tekst zawierający poprawną liczbę, ale odrzuci między innymi litery, nieprawidłowe separatory oraz wartości wykraczające poza zakres danego typu.
SELECT CONVERT(int, '42') AS Liczba,
CONVERT(decimal(10,2), '1234.50') AS Kwota,
CONVERT(varchar(20), 9876) AS TekstowaWartosc;Przy kwotach używam zawsze typu decimal z określoną precyzją i skalą. Nie stosuję float do pieniędzy, ponieważ jest typem przybliżonym i może przechowywać wartości z drobnymi różnicami wynikającymi ze sposobu zapisu binarnego.
Długość tekstu ma znaczenie
Podczas konwersji do varchar albo nvarchar warto podać długość jawnie. W przeciwnym razie SQL Server może przyjąć domyślną długość, która nie pasuje do danego zastosowania, a przy zapisie do krótszej kolumny wartość może zostać obcięta albo zakończyć się błędem.
SELECT CONVERT(varchar(5), 'Kursdotnet.pl') AS SkroconyTekst,
CONVERT(varchar(30), 'Kursdotnet.pl') AS PelnyTekst;Pierwszy wynik zostanie ograniczony do pięciu znaków. To dobry przykład, dlaczego sama poprawność składni nie oznacza jeszcze poprawności biznesowej. W raportach takie obcięcie bywa trudne do zauważenia, szczególnie gdy wynik jest eksportowany dalej.
Konwersja znaków dziesiętnych
Format liczby musi odpowiadać regułom interpretowanym przez SQL Server. Tekst '1234.50' jest typowym bezpiecznym przykładem, ale dane w polskim formacie, na przykład '1 234,50', mogą wymagać wcześniejszego oczyszczenia.
SELECT CONVERT(decimal(12,2),
REPLACE(REPLACE('1 234,50', ' ', ''), ',', '.')) AS Kwota;Takie czyszczenie traktuję jako etap przygotowania danych, a nie uniwersalną metodę dla każdej lokalizacji. Przy większej liczbie źródeł lepiej ustalić jeden format wejściowy już na granicy systemu, zamiast powtarzać skomplikowane operacje w każdym zapytaniu.
Daty, godziny i style, które naprawdę mają znaczenie
Przy datach funkcja CONVERT jest szczególnie użyteczna, bo pozwala oddzielić wartość daty od jej prezentacji. Dla przykładu styl 23 zwraca format yyyy-mm-dd, styl 112 daje yyyymmdd, a styl 126 zapisuje datę i czas w formacie zbliżonym do ISO.
| Styl | Przykładowy wynik | Zastosowanie |
|---|---|---|
23 |
2026-09-16 |
Czytelna data bez godziny. |
112 |
20260916 |
Sortowanie i identyfikatory oparte na dacie. |
120 |
2026-09-16 14:30:00 |
Raporty i format techniczny bez strefy czasowej. |
126 |
2026-09-16T14:30:00 |
Integracje i wymiana danych w stylu ISO. |
103 |
16/09/2026 |
Prezentacja w popularnym formacie europejskim. |
DECLARE @Data datetime2 = '2026-09-16T14:30:45.123';
SELECT CONVERT(varchar(10), @Data, 23) AS Data,
CONVERT(varchar(8), @Data, 108) AS Godzina,
CONVERT(varchar(23), @Data, 126) AS DataISO;W praktyce rozdzielam dwie rzeczy. Datę przechowuję jako typ daty, a do tekstu konwertuję ją dopiero przy wyświetlaniu, eksporcie lub budowaniu komunikatu. Przechowywanie daty w kolumnie tekstowej utrudnia sortowanie, filtrowanie i walidację.
Największa pułapka to niejednoznaczny zapis
Zapis typu 03/04/2026 może oznaczać 3 kwietnia albo 4 marca, zależnie od przyjętej interpretacji. Dlatego przy danych technicznych preferuję format yyyy-MM-dd lub ISO, a przy konwersji wejściowego tekstu jawnie wskazuję styl, jeśli jest dostępny dla danego przypadku.
SELECT CONVERT(date, '20260403', 112) AS BezpiecznaData,
CONVERT(date, '03/04/2026', 103) AS DataEuropejska;Unikam również dwucyfrowych lat. SQL Server ma regułę interpretacji takich wartości, ale wynik może nie odpowiadać intencji autora danych. Czterocyfrowy rok usuwa problem i kosztuje tylko dwa dodatkowe znaki.
TRY_CONVERT pomaga przeżyć kontakt z nieidealnymi danymi
Jeśli zwykły CONVERT nie potrafi zmienić wartości, zwraca błąd i może przerwać całe zapytanie. W przypadku importów, formularzy i danych pochodzących z zewnętrznych systemów często lepszym wyborem jest TRY_CONVERT, który zwraca NULL, gdy konwersja się nie powiedzie.
SELECT Wartosc,
TRY_CONVERT(int, Wartosc) AS Liczba
FROM (VALUES ('100'), ('250'), ('brak danych'), ('')) AS Dane(Wartosc);Dzięki temu można odseparować poprawne rekordy od problematycznych bez przerywania całego procesu. Samo NULL nie mówi jednak, dlaczego konwersja się nie udała, więc przy imporcie warto zachować wartość źródłową i oznaczyć rekord do dalszej kontroli.
Filtrowanie błędnych wartości
SELECT Wartosc
FROM ImportDanych
WHERE TRY_CONVERT(decimal(12,2), Wartosc) IS NULL
AND NULLIF(LTRIM(RTRIM(Wartosc)), '') IS NOT NULL;Ten warunek pomija puste wartości, ale pokazuje teksty, których nie można zamienić na kwotę. To praktyczniejszy wzorzec niż próba konwersji całej tabeli za pomocą funkcji, która zakończy się błędem przy pierwszym niepoprawnym rekordzie.
TRY_CONVERT nie rozwiązuje każdego problemu. Nieprawidłowy typ docelowy albo konwersja całkowicie niedozwolona przez SQL Server nadal może zakończyć się błędem. Funkcja chroni głównie przed niepoprawną zawartością danych, a nie przed błędną konstrukcją zapytania.
Wydajność i błędy, które pojawiają się w produkcji
Konwersja jest prosta składniowo, ale może mieć duży wpływ na plan wykonania. Najczęściej problem pojawia się wtedy, gdy funkcja obejmuje kolumnę używaną w filtrze, ponieważ SQL Server może nie wykorzystać efektywnie indeksu.
-- Mniej korzystny wzorzec
SELECT *
FROM Zamowienia
WHERE CONVERT(date, DataUtworzenia) = '2026-09-16';
-- Lepszy wzorzec dla kolumny datetime
SELECT *
FROM Zamowienia
WHERE DataUtworzenia >= '2026-09-16'
AND DataUtworzenia < '2026-09-17';Drugi wariant nie konwertuje każdej wartości w kolumnie i zachowuje przedział, który może zostać obsłużony przez indeks. Przy dużych tabelach różnica potrafi być bardzo wyraźna, dlatego przed użyciem funkcji w WHERE sprawdzam plan wykonania.
Konwersje niejawne
SQL Server potrafi konwertować typy automatycznie. Jeżeli porównuję kolumnę liczbową z tekstem albo mieszam typy varchar i nvarchar, silnik może wykonać konwersję niejawną, której nie widać bez analizy planu.
-- Kolumna KodProduktu ma typ int
SELECT *
FROM Produkty
WHERE KodProduktu = '100';Taki kod może zadziałać, ale jawne dopasowanie typu jest czytelniejsze i bezpieczniejsze. Zamiast polegać na automatyce, przekazuję parametr jako int albo jawnie konwertuję wartość wejściową przed porównaniem.
Przeczytaj również: Funkcja SQL - skalarna, tabelaryczna czy procedura?
Konwersja nie naprawia złego modelu danych
Jeżeli data jest przechowywana jako tekst, a kwota jako tekst z lokalnym separatorem, każda kwerenda musi wykonywać dodatkową pracę. Najlepsza konwersja to często ta, której nie trzeba wykonywać, bo dane już mają właściwy typ w tabeli.
W aplikacjach .NET pilnuję też, aby parametry zapytań miały odpowiednie typy. Parametr tekstowy porównywany z kolumną liczbową może wymusić dodatkowe przekształcenia, a przy dużych zbiorach danych przełożyć się na niepotrzebne obciążenie serwera.
Najbezpieczniejszy schemat pracy z CONVERT
Najpierw ustalam, czy zmiana typu jest potrzebna do obliczeń, filtrowania, czy tylko do prezentacji. Do prostych konwersji wybieram CAST, do formatowania dat i godzin CONVERT ze wskazanym stylem, a przy danych niepewnych używam TRY_CONVERT.
Daty zapisuję w typach date, datetime2 albo innym typie dobranym do wymagań, liczby finansowe w decimal, a tekst konwertuję z jawną długością. Taki zestaw zasad ogranicza błędy, poprawia czytelność kodu i pozwala uniknąć sytuacji, w której format prezentacji zaczyna decydować o poprawności danych.
Jeżeli zapytanie działa wolno, sprawdzam przede wszystkim, czy funkcja nie została nałożona na kolumnę filtrowaną lub łączoną. Sama składnia CONVERT jest prosta, ale dopiero właściwe miejsce jej użycia decyduje o tym, czy rozwiązanie będzie stabilne w realnej bazie.
