Типы данных и приведение типов
Преобразование одного типа данных в другой
Теория
Например, '2024-06-01' в типе DATE и '2024-06-01' в типе TEXT выглядят похоже только для нас, но для СУБД это разные значения. В первом случае это дата, во втором — просто строка. Для СУБД это две разные сущности, и обращаться с ними она будет по-разному.
Приведение типов - это операция, при помощи которой можно перевести (конвертировать) значение из одного типа данных в другой. То есть присвоить значению тот тип, в котором мы хотим использовать его дальше.
Это нужно в ситуациях, когда необходимо:
• текст превратить в число, чтобы считать;
• текст превратить в дату, чтобы сравнивать даты;
• дату превратить в timestamp, чтобы прибавить часы или интервал;
• число превратить в текст, если дальше его нужно обрабатывать как строку;
• значение перевести в numeric, если важна точность и предсказуемое округление.
Чаще всего в этой теме мы будем обсуждать типы:
• integer — целое число;
• numeric — точное дробное число;
• text — текст;
• date — только дата;
• timestamp — дата и время;
• boolean — логическое значение true или false.
В PostgreSQL есть две основные формы записи для преобразования типов:
• Функция CAST(value AS type);
• И оператор ::(двоеточие) value::type.
Обе конструкции делают одно и то же. Разница только в том, как это записано. CAST() выглядит более универсально, а запись через :: короче и в PostgreSQL встречается буквально на каждом шагу (:: является особенностью PostgreSQL и в других аналогичных СУБД вряд ли будет работать).
Важно: когда в SQL-запросе используется преобразование типов, в самой БД на самом деле ничего не изменяется. Там столбцы находятся в тех типах данных, в которых они там и были ранее (при создании). Результат преобразования в SQL-запросах мы получаем только лишь для чтения и анализа на мониторе нашего компьютера.
Синтаксис
SELECT CAST(value AS numeric), -- приводим значение value к типу numeric
value::numeric, -- то же самое, но через оператор ::, а не через CAST
some_timestamp::date, -- приводим дату и время к обычной дате
some_number::text -- приводим число к текстовому типу
FROM table_name; -- указываем таблицу, из которой берём данные
SELECT CAST('2024-06-01' AS date), -- приводим строку к типу date
'2024-06-01 12:30:00'::timestamp; -- приводим строку к типу timestamp
SQL
Короткая шпаргалка.
| Пример | Результат | Что делает |
|---|---|---|
| '42'::integer | 42 | Превращает текст в целое число. |
| CAST('12.675' AS numeric) | 12.675 | Превращает текст в точное дробное число. |
| order_date::date | Только дата | Убирает время у значения timestamp. |
| registration_date::timestamp | Дата + 00:00:00 | Превращает дату в дату со временем. |
| price::text | Текст с числом | Позволяет использовать число как текст. |
| CAST('2024-12-31' AS date) | 31.12.2024 | Превращает текст в дату. |
Основные моменты.
1. После значения мы указываем тип, в который хотим его перевести
Если вы пишете value::numeric, это читается так: возьми значение value и конвертируй его в значение типа numeric. Если вы пишете CAST(value AS numeric), смысл абсолютно тот же. Разница только во внешнем виде записи.
2. Приведение типа почти всегда делается не само по себе, а для какого-то осознанного шага
Обычно мы переводим значение в другой тип не потому, что нам просто захотелось, а потому что дальше какая-то функция, операция или выражение ждёт на входе другой тип. Например, функция LEFT() ожидает внутри значение текстового типа.
3. Не каждое значение можно перевести в любой тип
Если в текстовом типе находится число, его можно превратить в integer или numeric. Но если в текстовом типе находится что-то вроде 'abc', никакого волшебства не произойдёт. PostgreSQL не будет угадывать, что вы имели в виду, а просто вернёт ошибку, потому что 'abc'нельзя перевести в число. Таким образом, если вы хотите перевести какой-то столбец из текстового типа в числовой, и если хотя бы в одной строке этого столбца будут содержаться не числовые символы, то ничего не выйдет.
4. При переводе date в timestamp PostgreSQL добавляет время 00:00:00
При переводе значения из типа DATE в тип TIMESTAMP система прибавит к значению даты 00:00:00 и дальше будет воспринимать новое значение как тип TIMESTAMP.
5. Перевод в text удобен для вывода, но с ним можно поторопиться
Если вы преобразовали число или дату в текст, то дальше СУБД будет смотреть на это как на набор символов. Это удобно, если нужно склеить, обрезать или выполнить другие манипуляции с текстовой строкой. Но выполнить арифметические операции с такого рода значением уже не получится.
Примеры
1. Берём только дату из поля timestamp
🔄 Попробуйте изменить запрос:
- • Добавьте в SELECT операцию разности дат order_date::date - '2024-01-01'::date и назовите это diff_days
2. Превращаем дату в timestamp
🔄 Попробуйте изменить запрос:
- • Прибавьте к registration_date::timestamp интервал INTERVAL '12 hours' и посмотрите прибавится ли интервал
- • Попробуйте вместо INTERVAL '12 hours' прибавить INTERVAL '2 days'
3. Сначала задаём тип данных строке, а потом уже что-то с ней делаем
🔄 Попробуйте изменить запрос:
- • Замените '12500.75' на '12 500.75' и посмотрите, почему красивая для человека запись не нравится PostgreSQL
- • Замените INTERVAL '1 month' на INTERVAL '10 days' и сравните результат
4. Показываем случай, где numeric действительно нужен
🔄 Попробуйте изменить запрос:
- • Уберите последний ::numeric внутри ROUND() и посмотрите, какую ошибку вернёт PostgreSQL
- • Замените 2 на 1 и сравните, как меняется округление
5. Переводим число в текст, когда хотим обработать его как строку
🔄 Попробуйте изменить запрос:
- • Уберите ::text и посмотрите, почему LEFT перестанет работать
- • Замените LEFT на RIGHT и сравните результат
Типичные ошибки
Практика
Проверь себя
Ответьте на вопросы, чтобы закрепить материал: