PostgreSQL
 sql >> Baza danych >  >> RDS >> PostgreSQL

Przycinanie partycji na podstawie ograniczenia sprawdzającego nie działa zgodnie z oczekiwaniami

Twoja kolumna created_at to timestamp without time zone .

Ale now() zwraca timestamp with time zone . Wyrażenie now() - '1 hour'::interval jest zmuszany do timestamp [without time zone] , co niesie ze sobą dwa problemy :

1.) Nie prosiłeś o to, ale wyrażenie jest niewiarygodne. Jego wynik zależy od aktualnego ustawienia strefy czasowej sesji, w której wykonywane jest zapytanie. Szczegóły tutaj:

Aby wyrażenie było jasne, możesz użyć:

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

Lub po prostu (przeczytaj instrukcję tutaj) :

LOCALTIMESTAMP  -- explicitly take the local time

Rozważę pracę z timestamptz zamiast tego.
Żadne z nich nie rozwiązuje drugiego problemu:

2.) Odpowiedz na Twoje pytanie. Wykluczenie ograniczeń nie działa. Zgodnie z dokumentacją:

Pogrubiony nacisk na moje.

now() jest implementacją Postgresa CURRENT_TIMESTAMP . Jak widać w katalogu systemowym, jest on tylko STABLE , a nie IMMUTABLE :

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

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

Rozwiązania

1.) Możesz obejść to ograniczenie, podając stałą w WHERE warunek (który jest zawsze "niezmienny"):

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

2.) Lub „udając” niezmienną funkcję:

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

A potem:

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

Uważaj jednak, jak tego używasz:podczas gdy now() jest STABLE (nie zmienia się w czasie trwania transakcji), zmienia się zmieniać między transakcjami, więc uważaj, aby nie używać tego w przygotowanych instrukcjach (z wyjątkiem wartości parametru) lub indeksów lub czegokolwiek, co może cię ugryźć.

3.) Lub możesz dodać pozornie nadmiarową stałą WHERE klauzule do bieżącego zapytania, które pasują do ograniczenia na Twojej partycji:

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;

Upewnij się tylko, że now() - '1 hour'::interval wpadnie do właściwej partycji lub oczywiście nie uzyskasz żadnych wyników.

Poza tym:wolałbym użyć tego wyrażenia w CHECK ograniczenia i zapytanie. Łatwiejszy w obsłudze i robi to samo:

       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. SQL:Wybierz rekordy, w których WSZYSTKIE połączone rekordy spełniają pewien warunek

  2. Obsługa wielu dzierżawców z SQLAlchemy

  3. Błędy bazy danych w Django podczas używania wątków

  4. SpringBoot+Kotlin+Postgres i JSONB:org.hibernate.MappingException:Brak mapowania dialektu dla typu JDBC

  5. jaka jest sekwencja ucieczki łącznika (-) w PostgreSQL?