Po co w ogóle to wszystko — porównywanie i konwersja typów? Wyobraź sobie, że masz w tabeli string "42", a chcesz go porównać z liczbą 42. Na pierwszy rzut oka — to samo. Ale dla bazy danych to mogą być zupełnie różne rzeczy. PostgreSQL nie będzie się domyślał, co miałeś na myśli. I jeśli nie rozumiesz, jak dokładnie on porównuje wartości różnych typów, możesz dostać dziwny wynik albo nawet błąd.
To samo dotyczy konwersji. Czasem trzeba zamienić tekst na liczbę, żeby policzyć ile czegoś tam jest. A czasem odwrotnie — liczbę trzeba ładnie wyświetlić jako string. Albo wziąć datę i pokazać ją jako "01.01.2025", bo tak jest wygodniej dla użytkownika.
Albo inny przykład: masz dokładną wartość w NUMERIC, ale do obliczeń naukowych musisz użyć FLOAT. W takich sytuacjach bez jawnej konwersji — ani rusz.
Dobra wiadomość jest taka, że PostgreSQL świetnie sobie z tym radzi. Daje elastyczne i czytelne narzędzia do takich zadań. Najważniejsze — wiedzieć, jak ich używać i nie bać się trochę zajrzeć pod maskę. Tym się właśnie zajmiemy.
Porównywanie typów danych
PostgreSQL stara się być sprytny — jeśli widzi, że porównujesz np. INTEGER i NUMERIC, spokojnie sprowadzi je do wspólnego mianownika i wszystko porówna. To normalne, bo oba to liczby.
Ale jeśli spróbujesz porównać string z wartością boolowską (TEXT i BOOLEAN), baza danych już nie zrozumie, o co ci chodzi. Te typy mają zupełnie inną naturę i PostgreSQL po prostu rzuci błędem. To samo się stanie, jeśli spróbujesz porównać string "42" z liczbą 42 bez jawnego powiedzenia, że chcesz ten string zamienić na liczbę.
Jak to wygląda w praktyce? Oto przykład, który wywoła błąd:
SELECT '42' = 42; -- Błąd! String i liczba bez konwersji nie są porównywane
A tak wszystko zadziała jak trzeba:
SELECT '42'::INTEGER = 42; -- TRUE
Tutaj mówimy wprost: “Proszę, najpierw zamień '42' na liczbę”. Do tego właśnie służy składnia ::Typ, o której już wspominaliśmy. PostgreSQL lubi, gdy rozmawiasz z nim jasno.
Porównywanie typów liczbowych
Typy liczbowe (INTEGER, NUMERIC, REAL) najczęściej są ze sobą kompatybilne, więc można je porównywać bez większych problemów:
SELECT 42 = 42.0; -- TRUE
SELECT 42::REAL = 42.0; -- TRUE
SELECT 42.0::NUMERIC = 42; -- TRUE
Ale uważaj na liczby zmiennoprzecinkowe (REAL). Przez ograniczoną precyzję takie liczby mogą się zachowywać nieoczekiwanie. Na przykład:
SELECT 0.1 + 0.2 = 0.3; -- FALSE
Czy to nie najsłynniejsza zagadka programowania? Tutaj porównanie zwraca FALSE przez sposób przechowywania liczb zmiennoprzecinkowych w pamięci komputera.
Porównywanie typów tekstowych
Przy pracy z typami tekstowymi możesz porównywać CHAR, VARCHAR i TEXT, bo PostgreSQL automatycznie konwertuje je do kompatybilnych typów:
SELECT 'Hello' = 'Hello'::TEXT; -- TRUE
SELECT 'World'::CHAR(5) = 'World'::VARCHAR; -- TRUE
Zwróć uwagę na długość znaków w CHAR(n): jeśli string jest krótszy niż zadana długość, PostgreSQL dopełni go spacjami.
Konwersja typów danych
PostgreSQL daje kilka sposobów na konwersję typów danych. Omówimy dwa główne:
Sposób nr 1: Jawna konwersja (CAST)
Operator CAST pozwala określić, jak zamienić jeden typ na inny. Przykład:
SELECT CAST('42' AS INTEGER); -- Zamienia string '42' na liczbę 42
Ta metoda jest szczególnie wygodna, jeśli chcesz, żeby SQL był bardziej czytelny.
Sposób nr 2: Skrócony zapis (::)
PostgreSQL oferuje alternatywną składnię do konwersji typów — użycie ::. To ta sama operacja, tylko krócej zapisana:
SELECT '42'::INTEGER; -- To samo co CAST('42' AS INTEGER)
Automatyczna konwersja
W wielu przypadkach PostgreSQL automatycznie konwertuje dane. Na przykład, używając liczb w polach tekstowych:
SELECT '42' = 42::TEXT; -- TRUE
Ale poleganie na automatycznej konwersji nie zawsze jest bezpieczne, bo może być nieoczywiste dla innych programistów. Na przykład przy datach i stringach lepiej używać jawnej konwersji.
Przykłady konwersji różnych typów danych
Konwersja liczb na tekst
Czasem trzeba zamienić liczby na tekst (np. do budowania komunikatów):
SELECT 42::TEXT; -- Zamienia liczbę 42 na string '42'
SELECT 3.14::TEXT; -- Zamienia liczbę 3.14 na string '3.14'
Konwersja tekstu na liczby
Jeśli w stringu jest poprawna liczba, możesz go zamienić na typ liczbowy:
SELECT '123'::INTEGER; -- Zamienia string '123' na liczbę 123
SELECT '3.14'::FLOAT; -- Zamienia string '3.14' na liczbę 3.14
A co jeśli tekstu nie da się zamienić? Na przykład:
SELECT 'Hello'::INTEGER; -- Błąd: nie można zamienić 'Hello' na liczbę
Żeby uniknąć takich błędów, możesz użyć funkcji TRY_CAST() (od PostgreSQL 14) albo wcześniej sprawdzić dane.
Konwersja daty na tekst i odwrotnie
Przy konwersji dat możesz użyć funkcji TO_CHAR() i TO_DATE():
SELECT TO_CHAR(CURRENT_DATE, 'YYYY-MM-DD'); -- Zamienia datę na string
SELECT TO_DATE('2023-10-25', 'YYYY-MM-DD'); -- Zamienia string na datę
Konwersja między BOOLEAN a tekstem
Typ logiczny BOOLEAN też można zamieniać na stringi:
SELECT TRUE::TEXT; -- 'true'
SELECT FALSE::TEXT; -- 'false'
Albo odwrotnie:
SELECT 'true'::BOOLEAN; -- TRUE
SELECT 'false'::BOOLEAN; -- FALSE
Zwróć uwagę, że stringi typu 'yes' albo 'no' nie zostaną zamienione automatycznie.
Praktyka: wszystko na realnych przykładach
Stwórzmy tabelę, która pokazuje użycie różnych typów danych:
| id | number_as_text - TEXT | number_as_integer - INTEGER | date_as_text - TEXT | actual_date - DATE |
|---|---|---|---|---|
| 1 | 42 | 42 | 2023-10-25 | 2023-10-25 |
| 2 | 3.14 | NULL | 2023-10-24 | NULL |
| 3 | Hello | 123 | NULL | NULL |
Teraz wykonajmy operacje konwersji:
-- Konwersja tekstu na liczbę
SELECT number_as_text::INTEGER FROM data_types_demo WHERE number_as_text = '42';
-- Konwersja daty na tekst
SELECT TO_CHAR(actual_date, 'DD/MM/YYYY') FROM data_types_demo;
-- Konwersja stringa na datę
SELECT TO_DATE(date_as_text, 'YYYY-MM-DD') FROM data_types_demo;
Typowe błędy przy konwersji danych
Typowe błędy to:
- Próby konwersji danych, które nie pasują do oczekiwanego formatu (np. string
'Hello'doINTEGER). - Problemy z zaokrąglaniem i precyzją przy liczbach zmiennoprzecinkowych.
- Nieprawidłowe użycie formatów przy konwersji dat.
Żeby uniknąć błędów, warto:
- Zawsze sprawdzać dane przed konwersją.
- Używać funkcji obsługi błędów (
TRY_CASTalboCASE). - Jawnie podawać format przy konwersji dat.
-- Sprawdzanie danych przed konwersją
SELECT
CASE
WHEN number_as_text ~ '^\d+$' THEN number_as_text::INTEGER
ELSE NULL
END AS safe_integer
FROM data_types_demo;
Korzystaj z tego podejścia, żeby zabezpieczyć swoje zapytania przed niespodziankami!
Na tym etapie masz już podstawowe skille do porównywania i konwersji typów danych w PostgreSQL. Teraz tylko praktyka, praktyka i jeszcze raz praktyka. Do zobaczenia na kolejnych wykładach!
GO TO FULL VERSION