sql >> Database teknologi >  >> RDS >> PostgreSQL

Træk timer fra nu()-funktionen

Svar for timestamp

Du skal forstå arten af ​​datatyperne timestamp (timestamp without time zone ) og timestamptz (timestamp with time zone ). Hvis du ikke gør det, så læs dette først:

  • Ignorerer tidszoner helt i Rails og PostgreSQL

AT TIME ZONE konstruktion transformerer et timestamp til timestamptz , hvilket næsten helt sikkert er det forkerte træk for dit tilfælde:

where eventtime at time zone 'CET' between '2015-06-16 06:00:00'
                                       and '2015-06-17 06:00:00'

Først , det dræber ydeevnen. Anvender AT TIME ZONE til kolonnen eventtime gør udtrykket ikke sargerbart . Postgres kan ikke bruge almindelige indekser på eventtime . Men selv uden indeks er sargerbare udtryk billigere. Juster filterværdier i stedet for at manipulere hver rækkeværdi.
Du kunne kompensere med et matchende udtryksindeks, men det er nok bare en misforståelse og forkert alligevel.

Hvad sker der i det udtryk?

  1. AT TIME ZONE 'CET' transformerer timestamp værdi eventtime til timestamptz ved at tilføje tidsforskydningen for din aktuelle tidszone. Når du bruger en tidszone navn (ikke en numerisk offset eller en forkortelse), dette tager også højde for DST regler (sommertid), så du får en anden offset for "vinter" tidsstempler. Grundlæggende får du svaret på spørgsmålet:

    Hvad er det tilsvarende UTC-tidsstempel for det givne tidsstempel i den givne tidszone?

    Når du viser resultatet til brugeren er formateret som lokalt tidsstempel med den tilsvarende tidsforskydning for sessionens aktuelle tidszone. (Kan eller ikke være den samme som den, der bruges i udtrykket).

  2. Strengliteralerne på højre side har ingen datatype til sig, så typen er afledt af tildelingen i udtrykket. Da det er timestamptz nu er begge castet til timestamptz , forudsat den aktuelle tidszone for sessionen.

    Hvad er det tilsvarende UTC-tidsstempel for det givne tidsstempel for tidszoneindstillingen for den aktuelle session.

    Forskydningen kan variere med DST-regler.

Lang historie kort , hvis du altid arbejde med samme tidszone:CET eller 'Europe/Berlin' - det samme for nutidens tidsstempler, men ikke for historiske eller (muligvis) fremtidige, du kan bare skære bunden af.

Det andet problem med udtrykket:BETWEEN er næsten altid forkert med timestamp værdier. Se:

  • Optimer MELLEM datoerklæring
  • Find overlappende datointervaller i PostgreSQL
SELECT date_trunc('hour', eventtime) AS hour
     , count(DISTINCT serialnumber)  AS ct  -- sure you need distinct?
FROM   t_el_eventlog
WHERE  eventtime >= now()::date - interval '18 hours'
AND    eventtime <  now()::date + interval '6 hours'
AND    sourceid  =  44  -- don't quote the numeric literal
GROUP  BY 1
ORDER  BY 1;

now() er Postgres-implementeringen af ​​SQL-standarden CURRENT_TIMESTAMP . Begge returnerer timestamptz (ikke timestamp !). Du kan bruge enten.
now()::date svarer til CURRENT_DATE . Begge afhænger af den aktuelle tidszoneindstilling.

Du bør have et indeks af formularen:

CREATE INDEX foo ON t_el_eventlog(sourceid, eventtime)

Eller for at tillade kun indeksscanninger:

CREATE INDEX foo2 ON t_el_eventlog(sourceid, eventtime, serialnumber)

Hvis du opererer i forskellige tidszoner, bliver tingene mere komplicerede, og du bør bruge timestamptz til alt.

Alternativ til timestamptz

Før spørgsmålsopdateringen så det ud til, at tidszoner betyder noget. Når du har at gøre med forskellige tidszoner, "i dag" er en funktionel afhængighed af den aktuelle tidszone. Folk har en tendens til at glemme det.

For kun at arbejde med den aktuelle tidszoneindstilling for sessionen, brug samme forespørgsel som ovenfor. Hvis de udføres i en anden tidszone, er resultaterne i virkeligheden forkerte. (Gælder også ovenstående.)

For at garantere et korrekt resultat for en given tidszone ('Europa/Berlin' i dit tilfælde) uanset den aktuelle tidszoneindstilling for sessionen, skal du bruge dette udtryk i stedet:

    ((now() AT TIME ZONE 'Europe/Berlin')::date - interval '18 hours')
            AT TIME ZONE 'Europe/Berlin'  -- 2nd time to convert back

Vær opmærksom på, at AT TIME ZONE konstruktion returnerer timestamp for timestamptz input og omvendt.

Som nævnt i begyndelsen, alle de blodige detaljer her:

  • Ignorerer tidszoner helt i Rails og PostgreSQL


  1. Beregning af medianen med en dynamisk markør

  2. Hvordan omdøber man noget i SQL Server, der har firkantede parenteser i navnet?

  3. Enkel måde at beregne medianen med MySQL

  4. Vælg mellem agentbaseret og agentløs overvågning