Pchełki SQL: Próba konwersji

https://xpil.eu/r0l

Patrzymy na okno i wiemy od razu, że to jest okno, prawda? Patrzymy na głowę, nieważne czyją - i od razu wiemy, że to jest głowa. Patrzymy na wieszak i prawie na pewno nie pomylimy go z glebogryzarką. Potrafimy kategoryzować w zasadzie odruchowo i bez większych oporów.

Komputery, może poza naiwnymi namiastkami sztucznej inteligencji, które co i rusz ktoś gdzieś próbuje promować, tak nie mają. Im trzeba powiedzieć konkretnie: to jest liczba siedem. A to jest tekst "siedem". I tak dalej.

I tu pomału zbliżamy się do meritum dzisiejszego wpisu czyli konwersji typów danych. Żeby było nudniej ograniczymy się tylko li i wyłącznie do SQL Servera, bo właściwie dlaczego by nie?

Od dawien dawna można było w SQL-u wykonać operację CAST, "rzutującą" jeden typ danych w drugi, czyli po naszemu zamieniającą dane typu X na dane typu Y, w miarę możliwości z minimum uszkodzeń po drodze.

Potem pojawił się SQL Server od Małomiękkiego, a ponieważ Małomiękki lubi robić wszystko po swojemu, wykombinowali, że zamiast CAST lepiej będzie robić CONVERT. CONVERT robi to samo co CAST plus dodaje parę fontann ("fontanien"?) od siebie. Rzecz jasna Małomiękki nie byłby Małomiękkim gdyby czegoś nie spieprzył od czasu do czasu. Okazuje się, że CONVERT w pewnych konkretnych przypadkach potrafi odrobinę zmienić wartość konwertowanej przez siebie danej (chodzi głównie o te nieszczęsne dane zmiennoprzecinkowe, o których niedawno pisałem), podczas gdy CAST zachowa się poprawnie[j]. Ale to przypadki szczególne, ogólnie natomiast CONVERT jest funkcją bardzo wygodną i wypasioną po pachy.

Przykład: mamy kolumnę tekstową z danymi z jakiegoś zewnętrznego systemu. Dane te to daty zapisane w formacie MM-DD-YYYY (tak, urwał, najpierw numer miesiąca w roku, potem numer dnia w miesiącu, a potem rok - dalibóg nie wiem na co trzeba chorować, żeby ustalić taki standard, ale nie ma co płakać, mleko się już rozlało). No i teraz chcemy zamienić tę kolumnę z tekstu na datę:

SELECT CONVERT(DATE, [jakas_kolumna], 110)

Powyższe zapytanie skonwertuje nam dane z tekstu na datę, używając standardu numer 110 (lista standardów dat jest dostępna w dokumentacji Małomiękkiego, na przykład tutaj: https://msdn.microsoft.com/en-us/library/ms187928.aspx), czyli właśnie MM-DD-YYYY.

Wszystko pięknie, tylko co w sytuacji, kiedy ktoś nam podrzuci zgniłka?

Spróbujmy:

SELECT CONVERT(DATE, 'zgniłek', 110)

Msg 241, Level 16, State 1, Line 1
Conversion failed when converting date and/or time from character string.

Aha. Znaczy się, [wiel]bł[ą|ę]dem nas obrzucono. I co teraz?

Bazyle starej daty mogą spróbować skorzystać z funkcji ISDATE(), która sprawdzi, czy podany tekst jest datą. Można i tak - ale sprawa zaczyna się komplikować.

Można prościej. Począwszy od wersji SQL Server 2012 możemy używać odmiany funkcji CONVERT zatytułowanej TRY_CONVERT, czyli po naszemu "spróbuj skonwertować, a jak się nie uda to kula w łeb i do piachu" (zawsze podziwiałem język Yeats-a za zwięzłość). Innymi słowy TRY_CONVERT podejmie próbę konwersji i zwróci NULL jeżeli owa próba zakończy się niepowodzeniem:

SELECT TRY_CONVERT(DATE, 'zgniłek', 110)

Na wyjściu pokazuje się NULL, a w komunikatach - że zwrócono jeden rekord, bez żadnych błędów. Hura!

Bardzo wygodne.

Od niedawna używam TRY_CONVERT bezwstydnie w większości sytuacji, gdzie muszę załadować jakieś dane z zewnętrznego systemu, nad którym nie mam żadnej kontroli. I co odkryłem? Odsetek błędów spadł mi co najmniej o rząd wielkości. A jak się jakiś użyszkodnik potem przypier... znaczy, tego, uprzejmie zapyta dlaczego w tym okienku jest pusto, to mu łatwo dowodzę, że:

Ot, co.

https://xpil.eu/r0l

2 komentarze

  1. Całkiem sympatyczne rozwiązanie (Wrzucam do swojego głownego śmietnika) 🙂
    a tak na marginesie: fonnata odmienia się tak samo jak wanna – może tak będzie łatwiej 😉

Leave a Comment

Komentarze mile widziane.

Jeżeli chcesz do komentarza wstawić kod, użyj składni:
[code]
tutaj wstaw swój kod
[/code]

Jeżeli zrobisz literówkę lub zmienisz zdanie, możesz edytować komentarz po jego zatwierdzeniu.