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 / 333229
Accepted
J.D.
J.D.
Asked: 2023-11-18 01:36:46 +0800 CST2023-11-18 01:36:46 +0800 CST 2023-11-18 01:36:46 +0800 CST

Como resumir o Tempo Total distinto de um Evento ignorando sobreposições duplicadas em Tempos?

  • 772

Eu tenho a seguinte EventTimestabela:

DROP TABLE IF EXISTS dbo.EventTimes;
CREATE TABLE dbo.EventTimes
(
  EventTimeKeyId INT IDENTITY(1,1) PRIMARY KEY,
  EventId INT NOT NULL,
  StartTime TIME NOT NULL,
  EndTime TIME NOT NULL
);

Com os seguintes dados:

-- Event 1
INSERT INTO dbo.EventTimes (EventId, StartTime, EndTime)
VALUES 
  (1, '04:00:00', '14:00:00'), 
  (1, '06:00:00', '11:00:00'), 
  (1, '09:00:00', '12:00:00'), 
  (1, '13:00:00', '14:00:00'), -- Gap between this row and the next row
  (1, '02:30:00', '04:00:00'); -- Notice the half-hour on this one

-- Event 2
INSERT INTO dbo.EventTimes (EventId, StartTime, EndTime)
VALUES 
  (2, '00:00:00', '06:00:00'), -- Gap between this row and the next row
  (2, '09:00:00', '13:00:00'), 
  (2, '11:00:00', '15:00:00');

Perceber:

  • O mesmo Eventpode ter dois intervalos de tempo que se sobrepõem. Por exemplo, o mesmo Eventdas 4h às 14h e também das 6h às 11h.
  • Também pode haver lacunas entre os dois intervalos de tempo. Por exemplo, o mesmo Eventdas 13h às 14h e também das 14h30 às 16h.

Objetivo final:

Estou tentando calcular o valor TotalTimede um determinado Eventignorando o tempo de sobreposição duplicado. Por exemplo, para o conjunto de intervalos das 9h00 às 13h00 e das 11h00 às 15h00, o intervalo TotalTimedeverá ser de 6 horas (9h00 às 15h00). Por outro lado, também não quero contar o tempo nos intervalos entre dois intervalos de tempo. Portanto, para o conjunto de intervalos de 13h às 14h e de 14h30 às 16h, TotalTimedeve ser de 2,5 horas. (Observe que estes são apenas subconjuntos do exemplo completo acima, e o resultado final deve ser a soma de todos esses tempos únicos por Event.)

Nunca TotalTimedeve exceder 24 horas, esses tempos são todos dentro de um único dia (assim como o TIMEtipo de dados).

Resultados finais esperados para os exemplos fornecidos nos scripts acima:

Exemplos de resultados finais

dbfiddle.uk para referência.


Outras informações:

  • Se for mais fácil trabalhar com datas e horas, sinta-se à vontade para alterar os tipos de dados de TIMEpara DATETIME. Posso converter os resultados de volta, sem problemas.

  • Acredito que algum tipo de recursão seja necessária para resolver isso. Sinto que estou bem perto de uma solução, mas ainda não cheguei lá.

Em um caso como 2h30 - 4h e 4h - 14h, esperaria que o tempo total fosse de 11,5 horas.

sql-server
  • 2 2 respostas
  • 141 Views

2 respostas

  • Voted
  1. Best Answer
    Paul White
    2023-11-19T17:07:35+08:002023-11-19T17:07:35+08:00

    Toda a complexidade resulta dos intervalos sobrepostos.

    Se compactarmos os intervalos para que não haja sobreposições, a solução será um grupo e uma soma simples.

    O código a seguir usa a solução de empacotamento de intervalo de Itzik Ben-Gan :

    Intervalos de empacotamento é um problema clássico do T-SQL que envolve empacotar grupos de intervalos que se cruzam em seus respectivos intervalos contínuos. Eu me propus o desafio de tentar encontrar uma solução elegante que pudesse realizar a tarefa usando apenas um índice de suporte e uma única varredura dos dados, e encontrei uma.

    -- Itzik Ben-Gan's interval packing solution
    -- https://www.itprotoday.com/sql-server/new-solution-packing-intervals-problem
    WITH 
        C1 AS
        (
            SELECT 
                *,
                prvend = MAX(ET.EndTime) OVER (
                    PARTITION BY ET.EventId
                    ORDER BY ET.StartTime, ET.EndTime
                    ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING)
          FROM dbo.EventTimes AS ET
        ),
        C2 AS
        (
            SELECT 
                *,
                grp = SUM(isstart) OVER (
                    PARTITION BY C1.EventId
                    ORDER BY C1.StartTime, C1.EndTime
                    ROWS UNBOUNDED PRECEDING)
            FROM C1
            CROSS APPLY
            (
                VALUES
                (
                    CASE 
                        WHEN C1.StartTime <= C1.prvend 
                        THEN NULL 
                        ELSE 1 
                    END
                )
            ) AS A (isstart)
        ),
        Packed AS
        (
            SELECT 
                C2.EventId, 
                StartTime = MIN(C2.StartTime), 
                EndTime = MAX(C2.EndTime)
            FROM C2
            GROUP BY 
                C2.EventId, 
                C2.grp
        )
    -- Sum the packed intervals by EventId
    SELECT 
        P.EventId, 
        TotalTime = SUM(DATEDIFF(MINUTE, P.StartTime, P.EndTime)) / 60.0
    FROM Packed AS P
    GROUP BY 
        P.EventId;
    
    ID do Evento Tempo total
    1 11.500000
    2 12.000.000

    A classificação inicial pode ser evitada com um índice ativado (EventId, StartTime, EndTime).

    • 3
  2. Caleb Carl
    2023-11-18T02:40:37+08:002023-11-18T02:40:37+08:00

    Aqui está uma solução que usa Run Length Encoding para compactar intervalos de tempo sobrepostos -

    ESQUEMA E SAÍDA DESEJADA

    DROP TABLE IF EXISTS dbo.EventTimes;
    CREATE TABLE dbo.EventTimes
    (
      EventTimeKeyId INT IDENTITY(1,1) PRIMARY KEY,
      EventId INT NOT NULL,
      StartTime TIME NOT NULL,
      EndTime TIME NOT NULL
    );
    
    -- Event 1
    INSERT INTO dbo.EventTimes (EventId, StartTime, EndTime)
    VALUES 
      (1, '04:00:00', '14:00:00'), 
      (1, '06:00:00', '11:00:00'), 
      (1, '09:00:00', '12:00:00'), 
      (1, '13:00:00', '14:00:00'), -- Gap between this row and the next row
      (1, '02:30:00', '04:00:00'); -- Notice the half-hour on this one
    
    -- Event 2
    INSERT INTO dbo.EventTimes (EventId, StartTime, EndTime)
    VALUES 
      (2, '00:00:00', '06:00:00'), -- Gap between this row and the next row
      (2, '09:00:00', '13:00:00'), 
      (2, '11:00:00', '15:00:00');
    
    -- Final Results expected for these 2 examples
    SELECT 1 AS EventId, 11.5 AS TotalTime
    UNION ALL
    SELECT 2 AS EventId, 12 AS TotalTime;
    
    ID do Evento Tempo total
    1 11,5
    2 12,0

    SOLUÇÃO

    WITH x
    AS
    (
        SELECT EventID
             , StartTime
             , EndTime
             , IIF(
                   starttime <= MAX(EndTime) OVER (PARTITION BY EventID
                                                   ORDER BY StartTime
                                                   ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING
                                                  )
                   OR endtime >= MIN(starttime) OVER (PARTITION BY EventID
                                                      ORDER BY StartTime
                                                      ROWS BETWEEN 1 FOLLOWING AND UNBOUNDED FOLLOWING
                                                     )
                 , 1
                 , 0) AS grp
        FROM dbo.EventTimes
    )
       , j
    AS
    (
        SELECT EventID
             , MIN(starttime) AS stID
             , MAX(endtime) AS eID
        FROM x
        WHERE x.grp = 1
        GROUP BY x.EventID
               , x.grp
        UNION ALL
        SELECT x.EventID
             , x.starttime AS stID
             , x.endtime AS eID
        FROM x
        WHERE x.grp = 0
    )
    SELECT EventID
         , CAST(SUM(DATEDIFF(mi, j.stID, j.eID)) AS DECIMAL(5)) / 60 AS EventTime
    FROM j
    GROUP BY EventID;
    
    ID do Evento Hora do evento
    1 11.500000
    2 12.000.000

    DB Fiddle para referência

    • 2

relate perguntas

  • SQL Server - Como as páginas de dados são armazenadas ao usar um índice clusterizado

  • Preciso de índices separados para cada tipo de consulta ou um índice de várias colunas funcionará?

  • Quando devo usar uma restrição exclusiva em vez de um índice exclusivo?

  • Quais são as principais causas de deadlocks e podem ser evitadas?

  • Como determinar se um Índice é necessário ou necessário

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