Error date time field value out of range postgresql

Разбор ошибок Postgres


Содержание статьи

psql command not found

ERROR: character with byte sequence 0xd0 0x9a in encoding «UTF8» has no equivalent in encoding «WIN1252»

ERROR: database «db» is being accessed by other users

FATAL password authentication failed for user postgres

ERROR: could not open file «/home/user…» for reading: Permission denied

ERROR: COPY quote must be a single one-byte character

ERROR: date/time field value out of range

Job for postgresql.service failed because the control process exited with error code

psql: could not connect to server: No such file or directory

pg_basebackup: could not connect to server: No route to host

Failed to stop postgresql.service: Unit postgresql.service not loaded

ERROR: WAL level not sufficient for making an online backup

NOTICE: WAL archiving is not enabled

Ошибки

psql command not found

Вы хотите запустить Postgres скрипт из bash

andrey@olegovich-10:/mnt/c/Users/olegovich$ psql -h localhost -p 5432 -U andrei

но получаете эту ошибку

-bash: psql: command not found

Это значит, что путь до Postgres не прописан в $PATH

Чтобы узнать, что прописано в $PATH достаточно сделать

echo $PATH

/home/andrei/bin:/home/andrei/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/mnt/c/Program Files (x86)/Common Files/Oracle/Java/javapath_target_1128437:/mnt/c/ProgramData/Oracle/Java/javapath_target_5252250:/mnt/c/Windows/System32:/mnt/c/Windows:/mnt/c/Windows/System32/wbem:/mnt/c/Windows/System32/WindowsPowerShell/v1.0:/mnt/c/Program Files/OpenVPN/bin:/mnt/c/Program Files (x86)/Microsoft SQL Server/Client SDK/ODBC/130/Tools/Binn:/mnt/c/Program Files (x86)/Microsoft SQL Server/140/Tools/Binn:/mnt/c/Program Files (x86)/Microsoft SQL Server/140/DTS/Binn:/mnt/c/Program Files (x86)/Microsoft SQL Server/140/Tools/Binn/ManagementStudio:/mnt/c/Program Files/MiKTeX 2.9/miktex/bin/x64:/mnt/c/Users/andreyolegovich_ru/Documents/Software/axis2-1.6.2:/mnt/c/Users/andreyolegovich_ru/Documents/Software/axis2-1.6.2/bin:/mnt/c/Windows/System32/OpenSSH:/mnt/c/Program Files/TortoiseSVN/bin:/mnt/c/Program Files/Microsoft SQL Server/Client SDK/ODBC/130/Tools/Binn:/mnt/c/Program Files/Microsoft SQL Server/140/Tools/Binn:/mnt/c/Program Files/Microsoft SQL Server/140/DTS/Binn:/mnt/c/Program Files (x86)/Intel/Intel(R) Management Engine Components/DAL:/mnt/c/Program Files/Intel/Intel(R) Management Engine Components/DAL:/mnt/c/Program Files/TortoiseGit/bin:/mnt/c/Program Files/Git/cmd:/mnt/c/Program Files/nodejs:/mnt/c/Program Files/Intel/WiFi/bin:/mnt/c/Program Files/Common Files/Intel/WirelessCommon:/mnt/c/Program Files/PuTTY:/mnt/c/Users/andreyolegovich_ru/AppData/Local/Continuum/anaconda3:/mnt/c/Users/andreyolegovich_ru/AppData/Local/Continuum/anaconda3/Library/mingw-w64/bin:/mnt/c/Users/andreyolegovich_ru/AppData/Local/Continuum/anaconda3/Library/bin:/mnt/c/Users/andreyolegovich_ru/AppData/Local/Continuum/anaconda3/Scripts:/mnt/c/Users/andreyolegovich_ru/AppData/Local/Programs/Python/Python36/Scripts:/mnt/c/Users/andreyolegovich_ru/AppData/Local/Programs/Python/Python36:/mnt/c/Users/andreyolegovich_ru/AppData/Local/Microsoft/WindowsApps:/mnt/c/Users/andreyolegovich_ru/AppData/Local/atom/bin:/mnt/c/Users/andreyolegovich_ru/AppData/Local/Programs/Python/Python36-32:/mnt/c/Users/andreyolegovich_ru/AppData/Local/Programs/Python/Python36-32/Scripts:/mnt/c/Program Files (x86)/Nmap:/mnt/c/Program Files (x86)/Mozilla Firefox:/mnt/c/Users/andreyolegovich_ru/AppData/Local/Microsoft/WindowsApps:/mnt/c/Users/andreyolegovich_ru/AppData/Local/Programs/Fiddler:/mnt/c/Program Files/JetBrains/PyCharm Community Edition 2018.3.2/bin:/mnt/c/Users/andreyolegovich_ru/AppData/Roaming/npm:/mnt/c/Program Files/Intel/WiFi/bin:/mnt/c/Program Files/Common Files/Intel/WirelessCommon:/mnt/c/Users/andreyolegovich_ru/AppData/Local/Programs/Microsoft VS Code/bin:/snap/bin

ERROR: character with byte sequence 0xd0 0x9a in encoding «UTF8»

has no equivalent in encoding «WIN1252»

Скорее всего Вы создали базу данных, и даже смогли туда что-то импортировать, например, из .csv файла.

Но сделать SELECT * FROM table; уже не получается, потому что кодировка базы и кодировка файла не совпадают.

Возможно, Вы уже попробовали явно указать SET CLIENT_ENCODING TO ‘utf8’; при импорте файла. Но так как кодировка WIN1252
— это кодировка БД, способ не сработал.

Нужно привести файл и БД к одной кодировке — пересоздайте БД в utf8, например.

Как проверить кодировки я писал выше —

Проверка кодировок БД

Как указать кодировку при создании БД —

Создание БД

ERROR: database «db» is being accessed by other users

Если Вы делаете DROP DATABASE db; и получаете

ERROR: database «db» is being accessed by other users

DETAIL: There are 2 other sessions using the database.

Значит где-то ещё не закрыто подключение к БД. Например, Вы открывали её через pgAdmin.

Нужно найти это подключение и закрыть

FATAL password authentication failed for user postgres

Если вы логинитесь в pgAdmin, но не помните пароль — его можно поменять через терминал

sudo su — postgres

psql

postgres=# ALTER USER postgres PASSWORD ‘новый_пароль’;

ALTER ROLE

ERROR: could not open file «/home/user…» for reading: Permission denied

Если вы пытаетесь прочитать из файла, а получаете

ERROR: could not open file «/home/user/file.csv» for reading: Permission denied
HINT: COPY FROM instructs the PostgreSQL server process to read a file. You may want a client-side facility such as psql’s copy. SQL state: 42501

Значит у postgres недостаточно прав для чтения из файла. Простое добавление прав на чтение вроде

chmod +r file.csv

Проблему, скорее всего, не решит.

Как вариант — предлагаю переместить нужный файл в директорию /tmp

cp /home/user/file.csv /tmp

ERROR: COPY quote must be a single one-byte character

Если вы пытаетесь прочитать из файла, а получаете

ERROR: COPY quote must be a single one-byte character

SQL state: 0A000

Скорее всего присутствует какой-то лишний символ в QUOTE, например

QUOTE ‘»‘

Замените на

QUOTE ‘»‘

ERROR: date/time field value out of range

Если вы пытаетесь прочитать из .csv файла, а получаете

ERROR: date/time field value out of range: «» HINT: Perhaps you need a different «datestyle» setting. CONTEXT: «» SQL state: 22008

Скорее всего ваш текущий datestyle не совпадает с тем, который используется в .csv файле.

datestyle — это порядок записи даты. Может быть День — Месяц — Год (DDMMYYYY), Год — Месяц — День (YYYYMMDD) или,
например американский стиль Месяц — День — Год (MMDDYYYY)

Это всё актуально если тип столбца указан как дата date. Можно изменить тип на char тогда datestyle уже не нужно настраивать.

Стилей много и если они не совпадают — получается что месяц принимает значение больше 12.

Как вариант — можно перед выполнение скрипта временно изменить свой datestyle.

Например, если нужно импортировать данные из .csv с американским стилем — перед импортом добавьте

set datestyle to «US»;

psql: could not connect to server: No such file or directory

Если вы выполнили

psql

И получили ошибку

psql: could not connect to server: No such file or directory
Is the server running locally and accepting
connections on Unix domain socket «/var/run/postgresql/.s.PGSQL.5432»?

Очень часто данная ошибка возникает вследствии того, что не была инициализирована база
данных.

Выполните

postgresql-setup initdb

Initializing database … OK

pg_basebackup: could not connect to server: could not connect to server: No route to host

Если вы пытаетесь сделать реплику

pg_basebackup -h 192.168.56.109 -U repluser -D /var/lib/pgsql/data —xlog-method=stream

pg_basebackup: could not connect to server: could not connect to server: No route to host
Is the server running on host «192.168.56.109» and accepting
TCP/IP connections on port 5432?

На мастере

sudo firewall-cmd —zone=public —add-port=5432/tcp —permanent

success

sudo firewall-cmd —reload

success

sudo firewall-cmd —list-ports

3389/tcp 5432/tcp

Failed to stop postgresql.service: Unit postgresql.service not loaded

Причин может быть много но среди новичков самая распространённая — попытка остановить postgresql
из под пользователя postges

Например, в моём терминале я по приглашению bash-4.2$ вижу, что зашёл как postgres

Нужно выполнить

exit

Приглашение изменится на

[andrei@localhost ~]$

И затем уже можно останавливать сервер

sudo systemctl stop postgresql

sudo systemctl status postgresql

● postgresql.service — PostgreSQL database server
Loaded: loaded (/usr/lib/systemd/system/postgresql.service; disabled; vendor preset: disabled)
Active: inactive (dead)

Jun 09 12:20:24 localhost.localdomain systemd[1]: Unit postgresql.service entered failed state.
Jun 09 12:20:24 localhost.localdomain systemd[1]: postgresql.service failed.
Jun 09 12:21:59 localhost.localdomain systemd[1]: Starting PostgreSQL database server…
Jun 09 12:22:00 localhost.localdomain systemd[1]: Started PostgreSQL database server.
Jun 10 19:10:02 localhost.localdomain systemd[1]: Stopping PostgreSQL database server…
Jun 10 19:10:03 localhost.localdomain systemd[1]: Stopped PostgreSQL database server.
Jun 10 22:14:18 localhost.localdomain systemd[1]: Starting PostgreSQL database server…
Jun 10 22:14:19 localhost.localdomain systemd[1]: Started PostgreSQL database server.
Jun 11 10:11:15 localhost.localdomain systemd[1]: Stopping PostgreSQL database server…
Jun 11 10:11:16 localhost.localdomain systemd[1]: Stopped PostgreSQL database server.

ERROR: WAL level not sufficient for making an online backup

Вы хотите настроить онлайн бэкап, например с помощью команды

-bash-4.2$ psql -c «SELECT pg_start_backup(‘replbackup’);»

Но получаете ошибку

ERROR: WAL level not sufficient for making an online backup

HINT: wal_level must be set to «archive» or «hot_standby» at server start.

Нужно узнать расположение конфигурационного файла

postgresql.conf

-bash-4.2$ su — postgres -c «psql -c ‘SHOW config_file;'»

Password:
config_file
————————————-
/var/lib/pgsql/data/postgresql.conf
(1 row)

vi /var/lib/pgsql/data/postgresql.conf

Нужно установить wal_level = hot_standby

NOTICE: WAL archiving is not enabled

Вы заканчиваете бэкап, например с помощью команды

psql -c «SELECT pg_stop_backup();»

Но получаете предупреждение

NOTICE: WAL archiving is not enabled; you must ensure that all required WAL segments are copied through other means to complete the backup

  • Remove From My Forums
  • Question

  • I am trying to run the Select query(linked server) from SSMS to get the data from PostgreSQL on AWS cloud. My query is running fine in SSMS but as soon as I enter the following line of code

    and c.created_date >=concat(to_char(CURRENT_DATE — interval ‘7 day’, ‘yyyy-mm-dd’),’ 00:00:00′):: timestamp 
    and c.created_date <= concat(to_char(CURRENT_DATE — interval ‘1 day’,’yyyy-mm-dd’) ,’ 23:59:59′) ::timestamp 

    it starts giving me ERROR: date/time field value out of range: «2020-06-0700:00:00»;

    created_date field in my PostgreSQL is timestamp without timezone

    Which datatype should I chose which is compatible with SQL Server?

    • Edited by

      Sunday, June 14, 2020 6:28 AM

I’m getting this error trying to migrate MSSQL to Postgres

ERROR Database error 22008: date/time field value out of range: «20180406034959»
HINT: Perhaps you need a different «datestyle» setting.
CONTEXT: COPY voldlayer, line 1, column lyr_crt_utc_time: «20180406034959»

The origin table is:

CREATE TABLE VOLDLAYER
(
    MD_REP_SID        NUMERIC(3)      NOT NULL,
    SRV_SID           NUMERIC(5)      NOT NULL,
    VSC_SID           NUMERIC(6)      NOT NULL,
    SITE_SID          NUMERIC(4)      NOT NULL,
    LYR_SID           NUMERIC(6)      NOT NULL,
    LYR_REFID         VARCHAR(255)    NOT NULL,
    LYR_GUID          CHAR(40)        NOT NULL,
    LYR_NAME          VARCHAR(255)    NOT NULL,
    LYR_CRT_TS        NUMERIC(14)     NOT NULL,
    LYR_CRT_DAY_ID    NUMERIC(8)      NOT NULL,
    LYR_CRT_MINUTE_ID NUMERIC(4)      NOT NULL,
    LYR_CRT_UTC_TIME  DATETIME        NOT NULL,
    LYR_MOD_TS        NUMERIC(14)     NOT NULL,
    LYR_MOD_DAY_ID    NUMERIC(8)      NOT NULL,
    LYR_MOD_MINUTE_ID NUMERIC(4)      NOT NULL,
    LYR_MOD_UTC_TIME  DATETIME        NOT NULL,
    LYR_OWN_ACC_GUID  CHAR(40)        NOT NULL,
    LYR_MOD_ACC_GUID  CHAR(40)        NOT NULL,
    LYR_TYPE_ID       NUMERIC(2)      NOT NULL,
    LYR_LOG_STATUS    NUMERIC(1)      NOT NULL,
    NO_LAYERS         NUMERIC(1)      NOT NULL,
    ROW_TS            DATETIME        DEFAULT GETDATE() NOT NULL,
  CONSTRAINT VOLDLAYER_PK PRIMARY KEY (MD_REP_SID, SRV_SID, VSC_SID, SITE_SID, LYR_SID)
);

The destination table is (Is not created by pgloader, was already created):

CREATE TABLE VOLDLAYER
(
    MD_REP_SID        NUMERIC(3)      NOT NULL,
    SRV_SID           NUMERIC(5)      NOT NULL,
    VSC_SID           NUMERIC(6)      NOT NULL,
    SITE_SID          NUMERIC(4)      NOT NULL,
    LYR_SID           NUMERIC(6)      NOT NULL,
    LYR_REFID         VARCHAR(255)    NOT NULL,
    LYR_GUID          CHAR(40)        NOT NULL,
    LYR_NAME          VARCHAR(255)    NOT NULL,
    LYR_CRT_TS        NUMERIC(14)     NOT NULL,
    LYR_CRT_DAY_ID    NUMERIC(8)      NOT NULL,
    LYR_CRT_MINUTE_ID NUMERIC(4)      NOT NULL,
    LYR_CRT_UTC_TIME  TIMESTAMP       NOT NULL,
    LYR_MOD_TS        NUMERIC(14)     NOT NULL,
    LYR_MOD_DAY_ID    NUMERIC(8)      NOT NULL,
    LYR_MOD_MINUTE_ID NUMERIC(4)      NOT NULL,
    LYR_MOD_UTC_TIME  TIMESTAMP       NOT NULL,
    LYR_OWN_ACC_GUID  CHAR(40)        NOT NULL,
    LYR_MOD_ACC_GUID  CHAR(40)        NOT NULL,
    LYR_TYPE_ID       NUMERIC(2)      NOT NULL,
    LYR_LOG_STATUS    NUMERIC(1)      NOT NULL,
    NO_LAYERS         NUMERIC(1)      NOT NULL,
    ROW_TS            TIMESTAMP       DEFAULT CURRENT_TIMESTAMP NOT NULL,
  CONSTRAINT VOLDLAYER_PK PRIMARY KEY (MD_REP_SID, SRV_SID, VSC_SID, SITE_SID, LYR_SID)
);

The load file is:

load database
     from {{DBPATH}}
     into postgresql://postgres:postgres@localhost:5432/postgres_test_pgloader
WITH
    include no drop,
    create no tables
cast
   type DATETIME to TIMESTAMP
including only table names like 'VOLDLAYER' in schema 'dbo'
BEFORE LOAD EXECUTE LDCreate.sql;

The problem is that this value ( lyr_crt_utc_time: «20180406034959») is not in this column in the origin table in in LYR_MOD_TS which have NUMERIC(14) value, not in LYR_CRT_UTC_TIME.
LYR_MOD_TS=20180406034959
LYR_CRT_UTC_TIME=2018-04-06 03:49:59.000
As a result of the error the complete table is not migrated.

В их внешнем облике ничто не вызывает подозрений. Более того, они даже кажутся тебе хорошо и давно знакомыми. Но это только до тех пор, пока ты их не проверишь. Вот тут-то они и проявят свою коварную сущность, сработав совсем не так, как ты ожидал. А иногда выкидывают такое, от чего волосы просто встают дыбом — к примеру, теряют доверенные им секретные данные. Когда ты делаешь им очную ставку, они утверждают, что не знают друг друга, хотя в тени усердно трудятся под одним колпаком. Пора уже наконец-то вывести их на чистую воду. Давайте же и мы разберемся с этими подозрительными типами.

Типизация данных в PostgreSQL, при всей своей логичности, действительно преподносит порой очень странные сюрпризы. В этой статье мы постараемся прояснить некоторые их причуды, разобраться в причине их странного поведения и понять, как не столкнуться с проблемами в повседневной практике. Сказать по правде, я составил эту статью в том числе и в качестве некоего справочника для самого себя, справочника, к которому можно было бы легко обратиться в спорных случаях. Поэтому он будет пополняться по мере обнаружения новых сюрпризов от подозрительных типов. Итак, в путь, о неутомимые следопыты баз данных!

Досье номер один. real/double precision/numeric/money

Казалось бы, числовые типы наименее проблемные с точки зрения сюрпризов в поведении. Но как бы не так. Поэтому с них и начнем. Итак…

Разучились считать

SELECT 0.1::real = 0.1

?column?
boolean
---------
f

В чем дело? В том, что PostgreSQL приводит нетипизированную константу 0.1 к типу double precision и пытается сравнить ее с 0.1 типа real. А это абсолютно разные значения! Суть в представлении вещественных чисел в машинной памяти. Поскольку 0.1 невозможно представить в виде конечной двоичной дроби (это будет 0.0(0011) в двоичном виде), числа с разной разрядностью будут отличаться, отсюда и результат, что они не равны. Вообще говоря, это тема для отдельной статьи, подробнее писать тут не буду.

Откуда ошибка?

SELECT double precision(1)

ERROR:  syntax error at or near "("
LINE 1: SELECT double precision(1)
                               ^
********** Ошибка **********
ERROR: syntax error at or near "("
SQL-состояние: 42601
Символ: 24

Многие знают, что PostgreSQL допускает функциональную запись приведения типов. То есть можно написать не только 1::int, но и int(1), что будет равнозначно. Но только не для типов, название которых состоит из нескольких слов! Поэтому, если вы хотите привести числовое значение к типу double precision в функциональном виде, используйте алиас этого типа float8, то есть SELECT float8(1).

Что больше бесконечности?

SELECT 'Infinity'::double precision < 'NaN'::double precision

?column?
boolean
---------
t

Вон оно как! Оказывается, есть нечто, большее бесконечности, и это NaN! При этом документация PostgreSQL честными глазами смотрит на нас и утверждает, что NaN заведомо больше любого другого числа, а, следовательно, бесконечности. Справедливо и обратное для -NaN. Привет, любители матанализа! Но надо помнить, что все это действует в контексте вещественных чисел.

Округление глаз

SELECT round('2.5'::double precision)
     , round('2.5'::numeric)

      round      |  round
double precision | numeric
-----------------+---------
2                | 3

Еще один неожиданный привет от базы. И снова надо запомнить, что для типов double precision и numeric действуют разные округления. Для numeric — обычное, когда 0,5 округляется в большую сторону, а для double precision — округление 0,5 происходит в сторону ближайшего четного целого.

Деньги — это нечто особое

SELECT '10'::money::float8

ERROR:  cannot cast type money to double precision
LINE 1: SELECT '10'::money::float8
                          ^
********** Ошибка **********
ERROR: cannot cast type money to double precision
SQL-состояние: 42846
Символ: 19

По мнению PostgreSQL, деньги не являются вещественным числом. По мнению некоторых индивидуумов, тоже. Нам же надо помнить, что приведение типа money возможно только к типу numeric, равно как и к типу money можно привести только тип numeric. А вот с ним уже можно играться, как душе будет угодно. Но это будут уже не те деньги.

Smallint и генерация последовательностей

SELECT *
  FROM generate_series(1::smallint, 5::smallint, 1::smallint)

ERROR:  function generate_series(smallint, smallint, smallint) is not unique
LINE 2:   FROM generate_series(1::smallint, 5::smallint, 1::smallint...
               ^
HINT:  Could not choose a best candidate function. You might need to add explicit type casts.
********** Ошибка **********
ERROR: function generate_series(smallint, smallint, smallint) is not unique
SQL-состояние: 42725
Подсказка: Could not choose a best candidate function. You might need to add explicit type casts.
Символ: 18

Не любит PostgreSQL мелочиться. Какие такие последовательности на основании smallint? int, не меньше! Поэтому при попытке выполнения вышеприведенного запроса база пытается привести smallint к какому-то другому целочисленному типу, и видит, что таких приведений может быть несколько. Какое приведение выбрать? Это она решить не может, и поэтому падает с ошибкой.

Досье номер два. «char»/char/varchar/text

Ряд странностей присутствует и у символьных типов. Давайте тоже познакомимся с ними.

Это что за фокусы?

SELECT 'ПЕТЯ'::"char"
     , 'ПЕТЯ'::"char"::bytea
     , 'ПЕТЯ'::char
     , 'ПЕТЯ'::char::bytea

 char  | bytea |    bpchar    | bytea
"char" | bytea | character(1) | bytea
-------+-------+--------------+--------
 ╨     | xd0  | П            | xd09f

Что это за тип «char», что это за клоун? Нам таких не надо… Потому, что он прикидывается обычным char, даром что в кавычках. А отличается он от обычного char, который без кавычек, тем, что выводит только первый байт строкового представления, тогда как нормальный char выводит первый символ. В нашем случае первый символ — буква П, которая в unicode-представлении занимает 2 байта, о чем свидетельствует конвертация результата в тип bytea. А тип «char» берет только первый байт этого unicode-представления. Тогда зачем этот тип нужен? Документация PostgreSQL говорит, что это специальный тип, используемый для особых нужд. Так что он вряд ли нам потребуется. Но посмотрите ему в глаза и не ошибитесь, когда встретите его с его особенным поведением.

Лишние пробелы. С глаз долой, из сердца вон

SELECT 'abc   '::char(6)::bytea
     , 'abc   '::char(6)::varchar(6)::bytea
     , 'abc   '::varchar(6)::bytea

     bytea     |   bytea  |     bytea
     bytea     |   bytea  |     bytea
---------------+----------+----------------
x616263202020 | x616263 | x616263202020

Взгляните на приведенный пример. Я специально все результаты привел к типу bytea, чтобы было наглядно видно, что там лежит. Где хвостовые пробелы после приведения к типу varchar(6)? Документация лаконично утверждает: «При приведении значения character к другому символьному типу дополняющие пробелы отбрасываются». Эту нелюбовь надо запомнить. И заметьте, что если строковая константа в кавычках сразу приводится к типу varchar(6), концевые пробелы сохраняются. Такие вот чудеса.

Досье номер три. json/jsonb

JSON — отдельная структура, которая живет своей жизнью. Поэтому ее сущности и сущности PostgreSQL немного отличаются. Вот примеры.

Джонсон и Джонсон. Почувствуйте разницу

SELECT 'null'::jsonb IS NULL

?column?
boolean
---------
f

Все дело в том, что у JSON есть своя сущность null, которая не является аналогом NULL в PostgreSQL. В то же время, сам JSON-объект вполне может иметь значение NULL, поэтому выражение SELECT null::jsonb IS NULL (обратите внимание на отсутствие одинарных кавычек) на сей раз вернет true.

Одна буква меняет все

SELECT '{"1": [1, 2, 3], "2": [4, 5, 6], "1": [7, 8, 9]}'::json

                     json
                     json
------------------------------------------------
{"1": [1, 2, 3], "2": [4, 5, 6], "1": [7, 8, 9]}

---

SELECT '{"1": [1, 2, 3], "2": [4, 5, 6], "1": [7, 8, 9]}'::jsonb

             jsonb
             jsonb
--------------------------------
{"1": [7, 8, 9], "2": [4, 5, 6]}

Все дело в том, что json и jsonb — совершенно разные структуры. В json объект хранится как есть, а в jsonb он хранится уже в виде разобранной проиндексированной структуры. Именно поэтому во втором случае значение объекта по ключу 1 было заменено с [1, 2, 3] на [7, 8, 9], которое пришло в структуру в самом конце с тем же ключом.

С лица воды не пить

SELECT '{"reading": 1.230e-5}'::jsonb
     , '{"reading": 1.230e-5}'::json

          jsonb         |         json
          jsonb         |         json
------------------------+----------------------
{"reading": 0.00001230} | {"reading": 1.230e-5}

PostgreSQL в реализации JSONB меняет форматирование вещественных чисел, приводя их к классическому виду. Для типа JSON такого не происходит. Странно немного, но его право.

Досье номер четыре. date/time/timestamp

С типами даты/времени тоже есть некоторые странности. Посмотрим на них. Сразу оговорюсь, что некоторые из особенностей поведения становятся понятными, если хорошо понимать суть работы с часовыми поясами. Но это также тема для отдельной статьи.

Моя твоя не понимать

SELECT '08-Jan-99'::date

ERROR:  date/time field value out of range: "08-Jan-99"
LINE 1: SELECT '08-Jan-99'::date
               ^
HINT:  Perhaps you need a different "datestyle" setting.
********** Ошибка **********
ERROR: date/time field value out of range: "08-Jan-99"
SQL-состояние: 22008
Подсказка: Perhaps you need a different "datestyle" setting.
Символ: 8

Казалось бы, что тут непонятного? Но все же база не понимает, что мы тут поставили на первое место — год или день? И решает, что это 99 января 2008 года, что взрывает ей мозг. Вообще говоря, в случае передачи дат в текстовом формате нужно очень внимательно проверять то, насколько правильно база их распознала (в частности, анализировать параметр datestyle командой SHOW datestyle), поскольку неоднозначности в этом вопросе могут стоить очень дорого.

Ты откуда такой взялся?

SELECT '04:05 Europe/Moscow'::time

ERROR:  invalid input syntax for type time: "04:05 Europe/Moscow"
LINE 1: SELECT '04:05 Europe/Moscow'::time
               ^
********** Ошибка **********
ERROR: invalid input syntax for type time: "04:05 Europe/Moscow"
SQL-состояние: 22007
Символ: 8

Почему база не может понять явно указанное время? Потому что для часового пояса указана не аббревиатура, а полное наименование, которое имеет смысл только в контексте даты, поскольку учитывает историю изменения часовых поясов, а она без даты не работает. Да и сама формулировка строки времени вызывает вопросы — а что же на самом деле имел в виду программист? Поэтому тут все логично, если разобраться.

Что ему не так?

Представьте себе ситуацию. У вас в таблице есть поле с типом timestamptz. Вы хотите его проиндексировать. Но понимаете, что строить по этому полю индекс не всегда оправдано ввиду его высокой селективности (почти все значения этого типа будут уникальными). Поэтому вы решаете снизить селективность индекса, приведя этот тип к дате. И получаете сюрприз:

CREATE INDEX "iIdent-DateLastUpdate"
  ON public."Ident" USING btree
  (("DTLastUpdate"::date));

ERROR:  functions in index expression must be marked IMMUTABLE
********** Ошибка **********
ERROR: functions in index expression must be marked IMMUTABLE
SQL-состояние: 42P17

В чем дело? В том, что для приведения типа timestamptz к типу date используется значение системного параметра TimeZone, что делает функцию приведения типа зависимой от настраиваемого параметра, т.е. изменчивой (volatile). Такие функции в индексе недопустимы. В этом случае надо явно указывать, в каком часовом поясе производится приведение типа.

Когда now совсем даже не now

Мы привыкли, что now() возвращает текущую дату/время с учетом часового пояса. Но посмотрите на следующие запросы:

START TRANSACTION;
SELECT now();

            now
  timestamp with time zone
-----------------------------
2019-11-26 13:13:04.271419+03

...

SELECT now();

            now
  timestamp with time zone
-----------------------------
2019-11-26 13:13:04.271419+03

...

SELECT now();

            now
  timestamp with time zone
-----------------------------
2019-11-26 13:13:04.271419+03

COMMIT;

Дата/время возвращаются одинаковыми независимо от того, сколько времени прошло с момента предыдущего запроса! В чем дело? В том, что now() — это не текущее время, а время начала текущей транзакции. Поэтому в рамках транзакции оно не меняется. Любой запрос, запускаемый вне рамок транзакции, оборачивается в транзакцию неявно, поэтому мы и не замечаем, что время, выдаваемое простым запросом SELECT now(); на самом деле-то не текущее… Если хотите получить честное текущее время, нужно пользоваться функцией clock_timestamp().

Досье номер пять. bit

Strange a little bit

SELECT '111'::bit(4)

 bit
bit(4)
------
1110

С какой стороны следует добавлять биты в случае расширения типа? Кажется, что слева. Но только у базы на этот счет другое мнение. Будьте осторожны: при несоответствии количества разрядов при приведении типа вы получите совсем не то, что хотели. Это относится как к добавлению битов справа, так и к урезанию битов. Тоже справа…

Досье номер шесть. Массивы

Даже NULL не стрельнул

SELECT ARRAY[1, 2] || NULL

?column?
integer[]
---------
{1,2}

Как нормальные люди, воспитанные на SQL, мы ожидаем, что результатом этого выражения будет NULL. Но не тут-то было. Возвращается массив. Почему? Потому что в данном случае база приводит NULL к целочисленному массиву и неявно вызывает функцию array_cat. Но все равно остается неясным, почему этот «массивовый котик» не обнуляет массив. Такое поведение тоже надо просто запомнить.

Подведем итог. Странностей хватает. Большинство из них, конечно, не настолько критичны, чтобы говорить о вопиюще неадекватном поведении. А другие объясняются удобством использования или частотой их применимости в тех или иных ситуациях. Но в то же время неожиданностей много. Поэтому надо о них знать. Если найдете еще что-то странное или необычное в поведении каких-либо типов, пишите в комментариях, с удовольствием дополню имеющиеся на них досье.

Автор: Илья Щуров

Источник

In PostgreSQL, the make_timestamptz() function allows you to create a timestamp with time zone from its year, month, day, hour, minute and seconds fields, as well as an optional timezone field.

Syntax

The function has the following syntax:

make_timestamptz(year int, month int, day int, hour int, min int, sec double precision, [ timezone text ])

Where year, month, and day are integers representing the year, month, and day of the date, and hour is the hour part, min is the minutes part, and sec is the seconds part.

The hour and the minutes are provided as an integer, the seconds are provided as double precision.

The optional timezone argument is for the timezone. If it’s not specified, the current timezone is used.

The result is returned as a time with time zone.

Example

Here’s a basic example to demonstrate.

SELECT make_timestamptz(1999, 03, 14, 10, 35, 12.15);

Result:

1999-03-14 10:35:12.15+10

In this case I didn’t provide a timezone, so it used the current timezone.

We can verify the return type with the following query.

SELECT pg_typeof(make_timestamptz(1999, 03, 14, 10, 35, 12.15));

Result:

timestamp with time zone

The pg_typeof() function returns the data type of its argument, and so I passed make_timestamptz() as the argument.

Specify a Timezone

In this example I explicitly provide a timezone.

SELECT make_timestamptz(1999, 03, 14, 10, 35, 12.15, 'Indian/Mauritius');

Result:

1999-03-14 16:35:12.15+10

Here’s another example, but with various timezone values.

x
SELECT 
  make_timestamptz(2000, 01, 01, 00, 01, 00.00, 'ACDT'),
  make_timestamptz(2000, 01, 01, 00, 01, 00.00, 'ACST'),
  make_timestamptz(2000, 01, 01, 00, 01, 00.00, 'ACT'),
  make_timestamptz(2000, 01, 01, 00, 01, 00.00, '+01'),
  make_timestamptz(2000, 01, 01, 00, 01, 00.00, '-01'),
  make_timestamptz(2000, 01, 01, 00, 01, 00.00, 'NZ');

Result (using vertical output):

make_timestamptz | 1999-12-31 23:31:00+10
make_timestamptz | 2000-01-01 00:31:00+10
make_timestamptz | 2000-01-01 15:01:00+10
make_timestamptz | 2000-01-01 09:01:00+10
make_timestamptz | 2000-01-01 11:01:00+10
make_timestamptz | 1999-12-31 21:01:00+10

In this example I used x to enable expanded display (also known as “vertical output”) in order to make the results easier to read.

Entering x toggles expanded display (i.e. it enables and disables it).

See Return a List of Timezones Supported by PostgreSQL to get a list of valid timezones.

Out of Range

If any of the arguments are out of the range of the possible values for its date part, you’ll get an “out of range” error.

SELECT make_timestamptz(1999, 03, 32, 10, 35, 12.15);

Result:

ERROR: date field value out of range: 1999-03-32

In this case the day was 32, which is out of range, and so the message explained that the date field value was out of range.

If only the time field value is out of range, the error is worded accordingly.

SELECT make_timestamptz(1999, 03, 30, 10, 61, 12.15);

Result:

ERROR: time field value out of range: 10:61:12.15

In this case the minutes argument is 61, which is out of range.

Timestamp Without Timezone

To create a timestamp without a timezone, use the make_timestamp() function.

Понравилась статья? Поделить с друзьями:
  • Error database postgres already exists
  • Error database or disk is full
  • Error database is uninitialized and superuser password is not specified docker
  • Error database is mandatory on usermailbox
  • Error database driver unknown driver postgres forgotten import