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 / 141973
Accepted
Jmaurier
Jmaurier
Asked: 2016-06-23 11:19:13 +0800 CST2016-06-23 11:19:13 +0800 CST 2016-06-23 11:19:13 +0800 CST

Ajuda de consulta baseada em tempo

  • 772

Eu não consigo fazer isso funcionar da maneira que eu preciso. Eu tenho duas tabelas Assignmente Event.

Assignment
StartDate     EndDate       Equipment
4/1/2016      4/23/2016     1001
4/3/2016      4/10/2016     1002
3/30/2016     4/20/2016     1003

Event
StartDate     EndDate       Equipment    Event
4/2/2016      4/3/2016      1001         maintenance
4/8/2016      4/10/2016     1001         maintenance
4/4/2016      4/5/2016      1002         maintenance

Preciso juntar no equipamento e ter uma saída que divida o Assignment usando os eventos. Para esses dados de amostra, eu teria uma saída parecida com esta:

StartDate     EndDate       Equipment    EventStatus
4/1/2016      4/2/2016      1001         Active
4/2/2016      4/3/2016      1001         maintenance
4/3/2016      4/8/2016      1001         Active
4/8/2016      4/10/2016     1001         maintenance
4/10/2016     4/23/2016     1001         Active
4/3/2016      4/4/2016      1002         Active
4/4/2016      4/5/2016      1002         maintenance
4/5/2016      4/10/2016     1002         Active
3/30/2016     4/20/2016     1003         Active

Assim, para o equipamento número 1001; foi colocado em uma atribuição e teve manutenção duas vezes. Essa manutenção dividiu a tarefa em 5 partes da seguinte forma:

---------------------------------------------------------------------
|  Active  |maintenance|  Active  |maintenance|       Active        |
---------------------------------------------------------------------

Cada uma dessas partes deve ter sua própria linha com a data de início e término dessa seção. Como posso escrever uma consulta para fazer isso funcionar?

sql-server
  • 2 2 respostas
  • 91 Views

2 respostas

  • Voted
  1. Best Answer
    spaghettidba
    2016-06-24T00:45:12+08:002016-06-24T00:45:12+08:00

    Outra solução possível: (obrigado John Eisbrener pelos dados de amostra)

    DECLARE @Assignment TABLE
    (
        StartDate DATE,
        EndDate DATE,
        Equipment VARCHAR(50)
    );
    
    INSERT INTO @Assignment VALUES
        ('4/1/2016', '4/23/2016', '1001')
       ,('4/3/2016', '4/10/2016', '1002')
       ,('3/30/2016', '4/20/2016', '1003');
    
    
    DECLARE @Event TABLE
    (
        EventID INT NOT NULL IDENTITY(1,2),
        StartDate DATE,
        EndDate DATE,
        Equipment VARCHAR(50),
        [Event] VARCHAR(50)
    );
    
    INSERT INTO @Event 
        (StartDate, EndDate, Equipment, [Event])
    VALUES
        ('4/2/2016', '4/3/2016', '1001', 'maintenance')
       ,('4/8/2016', '4/10/2016', '1001', 'maintenance')
    -- Uncomment out prove it still works when stacking events back-to-back
    -- ,('4/11/2016', '4/12/2016', '1001', 'maintenance')
       ,('4/4/2016', '4/5/2016', '1002', 'maintenance');
    
    WITH AllEvents AS (
    
        -- Unpivot all the Assignments
        SELECT Equipment, V.EventDate, V.DateType, 'Active' AS EventType
        FROM @Assignment
        CROSS APPLY (
            VALUES
                (StartDate, 'start'),
                (EndDate, 'end')
        ) AS v(EventDate, DateType)
    
        UNION ALL 
    
        -- Unpivot all the Events
        SELECT Equipment, V.EventDate, V.DateType, [Event] AS EventType
        FROM @Event
        CROSS APPLY (
            VALUES
                (StartDate, 'start'),
                (EndDate, 'end')
        ) AS v(EventDate, DateType)
    
    )
    SELECT AE.Equipment,
        AE.EventDate AS StartDate,
        NextEvent.EventDate AS EndDate,
        EventStatus = 
            CASE 
                WHEN AE.DateType = 'end' 
                    AND AE.EventType = 'maintenance' THEN 'Active'
                ELSE AE.EventType
            END
    FROM AllEvents AE
    CROSS APPLY (
        -- Next Event by date
        SELECT TOP(1) EventDate, EventType, DateType
        FROM AllEvents
        WHERE Equipment = AE.Equipment
            AND EventDate > AE.EventDate
        ORDER BY EventDate
    ) AS NextEvent
    ORDER BY AE.Equipment, AE.EventDate
    
    • 2
  2. John Eisbrener
    2016-06-23T13:53:22+08:002016-06-23T13:53:22+08:00

    Isso é um pouco desajeitado, pois não consegui fazer uma função de janelamento (ou seja , DENSE_RANK , NTILE , RANK ou ROW_NUMBER ) funcionar como eu esperava, então tive que "projetar" uma via COALESCE e algumas personalizações na estrutura da tabela.

    A premissa básica aqui é que primeiro você precisa unir essas tabelas a uma tabela intermediária que contém uma lista de todos os dias (por exemplo, uma tabela adicional que criei, chamada #tmpDates). Essa é a base para a saída do relatório, pois agruparemos os registros para obter a saída especificada. Em seguida, trabalhamos na função de janela personalizada (usando COALESCE aqui) para que as etapas entre os dias de "manutenção" e os dias normais sejam enumeradas, mas para que funcione corretamente, tive que definir um campo de identificação na tabela de eventos com um valor de incremento de salto .

    O código em toda a sua glória horrenda está abaixo. Se você tiver dúvidas, me avise e farei o possível para esclarecer, mas isso é lixo ... lixo de trabalho. Espero que alguém consiga fazer isso funcionar com uma função de classificação em vez do meu horrível festival de hack-and-slash com COALESCE:

    -- Build out Tables to Show Example
    CREATE TABLE #tmpAssignment
    (
        StartDate DATE,
        EndDate DATE,
        Equipment VARCHAR(50)
    )
    
    INSERT INTO #tmpAssignment VALUES
        ('4/1/2016', '4/23/2016', '1001')
       ,('4/3/2016', '4/10/2016', '1002')
       ,('3/30/2016', '4/20/2016', '1003')
    
    -- NOTE: Make sure the identity field Skips a number to allow for windowing in the report
    CREATE TABLE #tmpEvent
    (
        EventID INT NOT NULL IDENTITY(1,2),
        StartDate DATE,
        EndDate DATE,
        Equipment VARCHAR(50),
        [Event] VARCHAR(50)
    )
    
    INSERT INTO #tmpEvent 
        (StartDate, EndDate, Equipment, [Event])
    VALUES
        ('4/2/2016', '4/3/2016', '1001', 'maintenance')
       ,('4/8/2016', '4/10/2016', '1001', 'maintenance')
    -- Uncomment out prove it still works when stacking events back-to-back
    -- ,('4/11/2016', '4/12/2016', '1001', 'maintenance')
       ,('4/4/2016', '4/5/2016', '1002', 'maintenance')
    
    -- Create a Join Table comprising of Dates
    CREATE TABLE #tmpDates
    (
        DateField   DATE
    )
    
    DECLARE @dField DATE
    SET @dField = '3/15/2016'
    
    SET NOCOUNT ON
    
    WHILE @dField < '5/15/2016'
    BEGIN
        INSERT INTO #tmpDates VALUES (@dField)
        SET @dField = DATEADD(DAY, 1, @dField)
    END
    
    SET NOCOUNT OFF
    
    
    ;WITH CTE_report
    AS
    (
        SELECT  d.DateField, a.Equipment, --e.[Event], e.EventID
            COALESCE(e.[Event], 'none') AS [Event], 
            COALESCE(
                -- Pull Event if Occurred
                e.EventID, 
                -- Window Before or In Between Events - This is horribly inefficient
                (SELECT MIN(EventID) - 1 FROM #tmpEvent te WHERE d.DateField < te.StartDate AND a.Equipment = te.Equipment), 
                -- Final Window After All Events - This is also horribly inefficient
                (SELECT MAX(EventID) + 1 FROM #tmpEvent te WHERE a.Equipment = te.Equipment), 
                -- No Events for a Given Assignment
                0) AS EventID
        FROM    #tmpDates d
                LEFT OUTER JOIN #tmpAssignment a
                    ON d.DateField >= a.StartDate
                        AND d.DateField <= a.EndDate
                LEFT OUTER JOIN #tmpEvent e
                    ON d.DateField >= e.StartDate
                        AND d.DateField <= e.EndDate
                        AND a.Equipment = e.Equipment
        WHERE   a.Equipment IS NOT NULL
    )
    SELECT  MIN(DateField) AS StartDate, MAX(DateField) AS EndDate, Equipment, [Event]
    FROM    CTE_report
    GROUP BY Equipment, [Event], [EventID]
    ORDER BY 3, 1
    
    
    -- Cleanup
    DROP TABLE #tmpAssignment
    DROP TABLE #tmpEvent
    DROP TABLE #tmpDates
    
    • 1

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