Поскольку годы, месяцы, кварталы не являются константами, нужны более сложные алгоритмы для их использования в операциях даты/времени. Возможно, вам следует для этих целей посмотреть функции, определенные пользователем (UDF), которые вы сможете использовать в качестве выражений в операндах.
Использование CAST() с типами дата/время
В некоторых местах этой главы вы встречали функцию CAST() в выражениях, содержащих типы данных даты и литералы даты. В настоящем разделе рассматриваются различные аспекты преобразования даты и времени более широко и подробно.
Преобразование между типами дата/время
Обычно преобразование из одного типа дата/время в другой возможно, если исходный тип дата/время содержит подходящий вид данных для помещения в выходной тип дата/время. Например, TIMESTAMP содержит данные, которые можно преобразовать в тип только даты DATE или только время TIME, В то время как тип TIME не содержит достаточно данных для преобразования в тип DATE. Firebird предоставляет возможность преобразовывать тип DATE В TIMESTAMP, присваивая времени значение полночи, и тип TIME в TIMESTAMP, выбирая дату из контекстной переменной CURRENT_DATE (серверное время). В табл. 10.9 представлены правила преобразования.
Таблица 10.9. Преобразования между типами дата/время в диалекте 3
Исходный тип | В тип TIMESTAMP | В тип DATE | В тип TIME |
TIMESTAMP | Недоступно | Да, преобразует дату, игнорируя время | Да, преобразует время, игнорируя дату |
DATE | Да, время устанавливается в значение полночи | Недоступно | Нет |
TIME | Да, дате присваивается значение CURRENT_DATE | Нет | Недоступно |
DATE + TIME | Да, CAST ( (DATEFIELD + TIMEFIELD AS TIMESTAMP) | Нет | Нет |
Преобразование типов даты в CHAR(n) и VARCHAR(n)
Используйте в операторах SQL-функцию CAST() для трансляции данных даты и времени в символьные типы данных.
Firebird преобразует типы дата и время в форматированные строки, в которых дата (если присутствует) представлена в установленном формате - в зависимости от диалекта - а время представлено в стандартном для Firebird формате: HH:MM:ss.nnnn. Необходимо использовать столбец, переменную типа CHAR или VARCHAR подходящего размера для получения желаемого вами результата.
Преобразование типов дата/время можно выполнять в оба строковых типа фиксированной длины CHAR и переменной длины VARCHAR. Поскольку размер преобразуемой строки заранее известен, CHAR имеет небольшое преимущество перед VARCHAR: использование CHAR при передаче по сети сэкономит вам два байта, которые добавляются к VARCHAR для хранения размера. "Правильный размер" зависит от диалекта, обратите на это внимание, VARCHAR может быть более подходящим при использовании в коде приложения, которое может обрабатывать оба диалекта.
Если символьное поле слишком мало для результата, то появится исключение переполнения. Пусть, вам нужно получить строку, содержащую только дату из TIMESTAMP. Использование для этого символьного контейнера меньшего размера не будет работать - CAST() не обрезает выходную строку. Необходимо выполнить двойное преобразование: вначале преобразование TIMESTAMP в DATE, а затем преобразование даты в символьный тип корректного размера - см. примеры в следующем разделе.
Диалект 3
Преобразование DATE или TIMESTAMP создает дату в формате ISO (CCYY-MM-DD). Полная длина выходной строки 10 символов для DATE и 11 - для TIMESTAMP (дата и один пробел перед временем). Нужно 13 символов для TIME или для времени в TIMESTAMP.
Например, выражение
SELECT CAST(timestamp_col as CHAR(24)) AS TstampTxt FROM RDB$DATABASE;
даст строку вроде следующей:
2004-06-25 12:15:45.2345
Это выдаст исключение переполнения:
SELECT CAST (timestamp_col as CHAR(20)) AS TstampTxt FROM RDB$DATABASE;
Двойное преобразование создает правильную строку:
SELECT FIRST 1 CAST (
CAST (timestamp_col AS DATE) AS CHAR(10)) FROM Table1;
Результатом будет:
2004-06-25
К сожалению, нет возможности путем прямого преобразования получить строку, содержащую дату плюс время без дробных долей секунды. Это может быть выполнено с использованием сложного выражения, включающего функции CAST() и EXTRACT(). Пример см. в одном из следующих подразделов разд. "Функция EXTRACT()".
Диалект 1
Дата в типе данных DATE диалекта 1 преобразуется в формат DD-MMM-CCYY, а не В формат ISO, как в диалекте 3. Например, вот это
SELECT CAST(dldate_col as CHAR(25)) AS DateTimeTxt FROM RDB$DATABASE;
даст
26-JUN-2004 12:15:45.2345
Следовательно, преобразование дат в диалекте 1 требует 11 символов вместо 10 плюс 1 символ пробела плюс 13 для времени - всего 25.
Более сложные выражения
Преобразование может использовать более сложные выражения в комбинации с другими выражениями, например:
SELECT CAST (10 + CAST(('TODAY') AS DATE) AS CHAR(25)) TEXTTIME FROM RDB$DATABASE;
или
SELECT CAST (10 + CURRENT_TIMESTAMP) AS DATE) AS CHAR(25)) TEXTTIME FROM RDB$DATABASE;
возвращает текстовую строку, показывающую дату на 10 дней позже текущей даты.
Преобразования между типами дата/время и другими типами данных
Любой символьный тип или выражение, чье содержание может быть выражено в правильном литерале даты, может быть преобразовано в соответствующий тип дата/время.
Типы данных времени и даты не могут быть участниками преобразований в типы или из типов SMALLINT, INTEGER, FLOAT, DOUBLE_PRECISION, NUMERIC, DECIMAL или BLOB.
Использование преобразований
Обмен данными дата/время с другими приложениями
Импорт данных дата/время, созданных в другом месте, - например, в другой системе базы данных, во включающем языке или в устройстве получения даты - обычно требует некоторых предварительных действий, прежде чем данные дата/время могут быть помещены в базу данных Firebird.
Большинство включающих языков программирования не поддерживают типы данных DATE, TIME и TIMESTAMP, представляя их внутренне в виде строк или структур. Устройства ввода данных обычно сохраняют дату и время в строках различных форматов и стилях. Типы дата/время чаще всего являются несовместимыми в различных базах данных.
Преобразование обычно требует вычисления и декодирования содержимого элементов даты в исходных данных. Второй частью процесса является реконструкция декодированных элементов и передача их SQL Firebird каким-нибудь способом. Во включающем языке, в котором не существует никакого способа передачи типов данных дата/время Firebird, использование функции CAST() в комбинации с допустимыми текстовыми строками для обработки в Firebird в качестве литералов даты может оказаться очень полезным.
В некоторых случаях сохранение внешних данных в текстовых файлах в форматах литералов даты может быть лучшим решением. Firebird может открывать такие файлы, как входные таблицы в модулях на серверной стороне - хранимые процедуры или триггеры - и использовать CAST() и другие функции для обработки данных в столбцах даты/времени в родных таблицах. Более подробную информацию см. в разд. "Использование внешних файлов в качестве таблицы " главы 16.
Функция CAST() также может быть использована для подготовки внутренних данных для экспорта.
Использование в выражениях условия поиска
Такие ситуации появляются, когда использование CAST() в предложении WHERE с типами дата/время решает логические проблемы сравнения столбца одного типа со столбцом другого типа данных.
Предположим, что нам нужно объединить таблицу покупателей, которая содержит столбец BALANCE_DATE типа DATE с таблицей транзакций покупателя, которая имеет столбец TRANSUDATE типа TIMESTAMP. Нам нужно создать предложение WHERE, которое выбирает набор данных, содержащий неоплаченные транзакции для текущего покупателя, появившиеся не позднее BALANCE_DATE. Мы можем попытаться:
SELECT ...
WHERE COST_TRANS.TRANSDATE <= CUSTOMER.BALANCE_DATE ;
Этот критерий не даст нам того, что мы хотим! Он найдет все строки транзакций после полуночи даты BALANCE_DATE, потому что он вычислит BALANCE_DATE с временем 00:00:00. Любая транзакция после полуночи этой даты не будет соответствовать критерию поиска.
Что мы действительно хотим, так это включить все транзакции, где дата из TRANS DATE соответствует BALANCE_DATE. Преобразование TRANSUDATE в тип DATE сохраняет день:
SELECT ...
WHERE CAST (CUST_TRANS.TRANSDATE AS DATE) <= CUSTOMER.BALANCE_DATE;