AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / dba / Perguntas / 152929
Accepted
beldaz
beldaz
Asked: 2016-10-21 15:11:02 +0800 CST2016-10-21 15:11:02 +0800 CST 2016-10-21 15:11:02 +0800 CST

Divisão de intervalo do PostgreSQL

  • 772

Isso apareceu algumas vezes, por exemplo, no grupo de notícias postgresql e no wiki . Em geral, a relação entre diferentes intervals pode não ser bem definida - um mês pode ter diferentes números de dias, dependendo de qual mês (e ano) está sendo considerado. Mas às vezes é necessário calcular quantos intervalos ocorrem entre dois pontos no tempo, por exemplo (exemplo simplificado):

CREATE TABLE recordings(tstart timestamp, tend timestamp, interval ticklength);

SELECT (tend - tstart) / ticklength AS numticks
FROM recordings;

Isso não é permitido no PostgreSQL porque é uma divisão entre dois intervalos, que não teria um comportamento geral bem definido pelos motivos acima. Existe uma solução alternativa para quando um intervalo pode ser convertido em segundos, mas qual é a melhor maneira quando não é o caso, por exemplo, quando o intervalo é da ordem de milissegundos?

postgresql time
  • 4 4 respostas
  • 5518 Views

4 respostas

  • Voted
  1. Best Answer
    beldaz
    2016-10-24T14:19:16+08:002016-10-24T14:19:16+08:00

    Como @a_horse_with_no_name menciona em seu comentário, a divisão pode ser obtida pela conversão em milissegundos.

    SELECT 
      (1000*EXTRACT(EPOCH FROM tend - tstart) 
        + EXTRACT(MILLISECOND FROM tend - tstart))
      / (1000*EXTRACT(EPOCH FROM ticklength) 
        + EXTRACT(MILLISECOND FROM ticklength)) AS numticks
    FROM recordings;
    
    • 3
  2. Teddy
    2017-07-27T00:52:36+08:002017-07-27T00:52:36+08:00

    A solução alternativa à qual você vincula (extrair épocas dos intervalos e dividir por eles) funciona bem para segundos e milissegundos. Portanto, se esse for o seu caso de uso, use-o.

    Se você quiser ser mais geral e retornar NULL quando nenhuma resposta for possível, porém, temos que ser mais complexos:

    -- An interval consists of a number of years, months, days, hours,
    -- minutes, and seconds.  The problem of dividing two intervals lies
    -- in the fact that "one month" is not a fixed number of days.
    -- Therefore, dividing, say, P1M with P1D would not make sense.
    
    CREATE OR REPLACE FUNCTION interval_months_part(INTERVAL)
            RETURNS INTEGER AS $$
            SELECT EXTRACT(years FROM $1)::INTEGER * 12
                    + EXTRACT(months FROM $1)::INTEGER
    $$ LANGUAGE SQL IMMUTABLE STRICT;
    COMMENT ON FUNCTION interval_months_part(INTERVAL) IS
    'Years plus months as a whole number of months';
    
    CREATE OR REPLACE FUNCTION interval_seconds_part(INTERVAL)
            RETURNS DOUBLE PRECISION AS $$
            SELECT EXTRACT(days FROM $1) * 24 * 60 * 60
                    + EXTRACT(hours FROM $1) * 60 * 60
                    + EXTRACT(mins FROM $1) * 60
                    + EXTRACT(secs FROM $1);
    $$ LANGUAGE SQL IMMUTABLE STRICT;
    COMMENT ON FUNCTION interval_months_part(INTERVAL) IS
    'Days, hours, minutes, and seconds as seconds';
    
    -- If we can divide exactly, do so.  Otherwise return NULL, unless
    -- fudging is requested, in which case all months are implicitly
    -- assumed to be 30 days, (except for 12 months, which become 365.25
    -- days), by extracting and dividing the epochs.
    CREATE OR REPLACE FUNCTION interval_divide(dividend INTERVAL,
                                                    divisor INTERVAL,
                                                    fudge BOOL DEFAULT false)
            RETURNS DOUBLE PRECISION AS $$
            SELECT CASE WHEN interval_months_part($1) = 0
                                    AND interval_months_part($2) = 0
                            THEN interval_seconds_part($1)
                                    / interval_seconds_part($2)
                            WHEN interval_seconds_part($1) = 0
                                    AND interval_seconds_part($2) = 0
                            THEN CAST(interval_months_part($1)
                                            AS DOUBLE PRECISION)
                                    / interval_months_part($2)
                            WHEN fudge
                                    THEN EXTRACT(EPOCH FROM $1)
                                            / EXTRACT(EPOCH FROM $2)
                            ELSE NULL
                            END;
    $$ LANGUAGE SQL IMMUTABLE STRICT;
    
    • 1
  3. Itay Grudev
    2021-02-23T08:42:14+08:002021-02-23T08:42:14+08:00

    Embora, por enquanto, o Postgres não pareça suportar divisão de intervalo, é claro que você pode converter esses intervalos em um número que pode dividir - como segundos.

    As outras respostas propostas sugerem: EXTRACT(MILLISECOND FROM interval '1 day'), mas descobri que isso às vezes retorna 0. E, claro, não se pode dividir por zero.

    Mas o seguinte funciona muito melhor e é mais confiável:

    SELECT EXTRACT(EPOCH FROM interval '17 days') / EXTRACT(EPOCH FROM interval '1 day');
    

    Então, para dividir intervalos - extraia o número de segundos no intervalo usando EXTRACT(EPOCH, interval)e divida-os.

    • 1
  4. Gunther Schadow
    2022-08-09T02:08:27+08:002022-08-09T02:08:27+08:00

    A resposta aceita está errada.

    Não acho que você deva adicionar os milissegundos de extração do intervalo, pois a época de extração do intervalo já extrai segundos com milissegundos. A documentação diz:

    epoch -- [...] para valores de intervalo, o número total de segundos no intervalo

    milissegundos -- O campo de segundos, incluindo partes fracionárias, multiplicado por 1000. Observe que isso inclui segundos completos.

    Você pode experimentar:

    select extract('epoch' from '1987 years 6 months 5 days 8 hours 15 min 30.123 seconds'::interval);
    
        date_part
    -----------------
     62720964930.123
    

    você vê como o ".123" aqui nos diz que os milissegundos já foram incluídos?

    Acho que já passou da hora de adicionar o operador de divisão para intervalos.

    CREATE OR REPLACE FUNCTION interval_div(interval, interval) RETURNS float8 AS $$
      SELECT EXTRACT(EPOCH FROM $1) / EXTRACT(EPOCH FROM $2)
    $$ LANGUAGE SQL IMMUTABLE STRICT;
    
    CREATE OPERATOR / ( 
       FUNCTION = interval_div,
       LEFTARG = interval, 
       RIGHTARG = interval );
    

    E com isso:

    select '1 hour'::interval / '1 second'::interval;
     ?column?
    ----------
         3600
    
    select '1 hour'::interval / '1.123 second'::interval;
         ?column?
    -------------------
     3205.699020480855
    

    Algumas ressalvas:

    select '1 month'::interval / '1 day'::interval;
     ?column?
    ----------
           30
    
    integrator=> select '12 month'::interval / '1 day'::interval;
     ?column?
    ----------
       365.25
    

    Ano juliano, mas não um mês juliano médio.

    select '1 year'::interval / '1 day'::interval / 12;
     ?column?
    ----------
      30.4375
    
    • 0

relate perguntas

  • Posso ativar o PITR depois que o banco de dados foi usado

  • Práticas recomendadas para executar a replicação atrasada do deslocamento de tempo

  • Os procedimentos armazenados impedem a injeção de SQL?

  • Sequências Biológicas do UniProt no PostgreSQL

  • Qual é a diferença entre a replicação do PostgreSQL 9.0 e o Slony-I?

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host

    • 12 respostas
  • Marko Smith

    Como fazer a saída do sqlplus aparecer em uma linha?

    • 3 respostas
  • Marko Smith

    Selecione qual tem data máxima ou data mais recente

    • 3 respostas
  • Marko Smith

    Como faço para listar todos os esquemas no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Listar todas as colunas de uma tabela especificada

    • 5 respostas
  • Marko Smith

    Como usar o sqlplus para se conectar a um banco de dados Oracle localizado em outro host sem modificar meu próprio tnsnames.ora

    • 4 respostas
  • Marko Smith

    Como você mysqldump tabela (s) específica (s)?

    • 4 respostas
  • Marko Smith

    Listar os privilégios do banco de dados usando o psql

    • 10 respostas
  • Marko Smith

    Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Como faço para listar todos os bancos de dados e tabelas usando o psql?

    • 7 respostas
  • Martin Hope
    Jin conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host 2014-12-02 02:54:58 +0800 CST
  • Martin Hope
    Stéphane Como faço para listar todos os esquemas no PostgreSQL? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh Por que o log de transações continua crescendo ou fica sem espaço? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland Listar todas as colunas de uma tabela especificada 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney O MySQL pode realizar consultas razoavelmente em bilhões de linhas? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx Como posso monitorar o andamento de uma importação de um arquivo .sql grande? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison Como você mysqldump tabela (s) específica (s)? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Jonas Como posso cronometrar consultas SQL usando psql? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas Como faço para listar todos os bancos de dados e tabelas usando o psql? 2011-02-18 00:45:49 +0800 CST

Hot tag

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve