PostgreSQL
 sql >> база данни >  >> RDS >> PostgreSQL

Подрязването на дял въз основа на ограничение за проверка не работи според очакванията

Вашата колона created_at е timestamp without time zone .

Но now() връща timestamp with time zone . Изразът now() - '1 hour'::interval е принуден към timestamp [without time zone] , което носидва проблема :

1.) Не сте поискали това, но изразът е ненадежден. Резултатът зависи от текущата настройка на часовата зона на сесията, в която се изпълнява заявката. Подробности тук:

За да направите израза ясен, можете да използвате:

now() AT TIME ZONE 'Europe/London' -- your time zone here

Или просто (прочетете ръководството тук) :

LOCALTIMESTAMP  -- explicitly take the local time

Бих обмислил работа с timestamptz вместо това.
Нито едно от двете не решава втория ви проблем:

2.) Отговор на вашия въпрос. Изключването на ограничение не работи. Съгласно документацията:

Удебелен акцент е мой.

now() е изпълнението на Postgres на CURRENT_TIMESTAMP . Както можете да видите в системния каталог, той е само STABLE , а не IMMUTABLE :

SELECT proname, provolatile FROM pg_proc WHERE proname = 'now';

proname | provolatile
--------+------------
now     | s              -- meaning: STABLE

Решения

1.) Можете да преодолеете ограничението, като предоставите константа в WHERE условие (което винаги е „неизменно“):

select count(*) from events
where created_at > '2015-05-25 15:49:20.037815'::timestamp;  -- derived from your example

2.) Или чрез „фалшифициране“ на неизменна функция:

CREATE FUNCTION f_now_immutable()
  RETURNS timestamp AS
$func$
SELECT now() AT TIME ZONE 'UTC'  -- your time zone here
$func$  LANGUAGE sql IMMUTABLE;

И след това:

select count(*) from events
where created_at > f_now_immutable() - interval '1 hour'

Все пак внимавайте как използвате това:докато now() е STABLE (не се променя по време на транзакцията), той се променя промяна между транзакциите, така че внимавайте да не използвате това в подготвени отчети (освен като стойност на параметър) или индекси или нещо друго, където може да ви ухапе.

3.) Или можете да добавите привидно излишна константа WHERE клаузи към текущата ви заявка, които съответстват на ограничението на вашия дял:

SELECT count(*)
FROM   events
WHERE  created_at > now() - '1 hour'::interval
AND    created_at >= '2015-04-01 00:00:00'::timestamp
AND    created_at <= '2015-04-30 23:59:59.999999'::timestamp;

Просто се уверете, че now() - '1 hour'::interval попада в правилния дял или очевидно няма да получите резултати.

Настрана:предпочитам да използвам този израз в CHECK ограничения и заявка. По-лесен за работа и прави същото:

       created_at >= '2015-04-01 0:0'::timestamp
AND    created_at <  '2015-05-01 0:0'::timestamp



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. TypeORM:Динамично задаване на схема на база данни за EntityManager (или хранилища) по време на изпълнение?

  2. Дублиращи се редове в таблица с първичен ключ.

  3. Postgres:Определяне на най-дългата поредица (в дни) на разработчик

  4. Как да получите елементи от Json масив в PostgreSQL

  5. PostgreSQL:Кой тип данни трябва да се използва за валута?