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 / coding / Perguntas / 79586970
Accepted
Enrico Gobbo
Enrico Gobbo
Asked: 2025-04-23 00:03:02 +0800 CST2025-04-23 00:03:02 +0800 CST 2025-04-23 00:03:02 +0800 CST

Função LAG aninhada (tipo isso)

  • 772

Eu tenho essa mesa

Código de Máquina DoCreation CódigoDeEstadoDaMáquina
DM139 2024-04-03 00:32:17.377 99
DM139 2024-04-03 00:32:49.080 0
DM139 2024-04-03 01:51:14.427 99
DM139 2024-04-03 01:51:45.643 0
DM139 2024-04-03 06:07:38.357 3
DM139 2024-04-03 06:07:39.043 0
DM139 2024-04-03 06:23:37.433 100
DM139 2024-04-03 06:23:43.697 0
DM139 2024-04-03 06:24:46.153 1
DM139 2024-04-03 06:25:02.467 0
DM139 2024-04-03 06:46:50.410 100
DM139 2024-04-03 06:47:29.247 0
DM139 2024-04-03 06:47:46.397 100
DM139 2024-04-03 06:53:47.160 0
DM139 2024-04-03 06:59:41.633 1
DM139 2024-04-03 06:59:54.550 0
DM139 2024-04-03 07:00:03.203 1
DM139 2024-04-03 07:00:06.437 0
DM139 2024-04-03 07:00:14.247 1
DM139 2024-04-03 07:00:17.683 2
DM139 2024-04-03 07:00:18.153 1
DM139 2024-04-03 07:00:18.840 2
DM139 2024-04-03 07:00:26.860 1
DM139 2024-04-03 07:00:46.387 2

cada registro representa uma "mudança de estado" da máquina específica DM139 onde

  • MachineCode = código da máquina (nvarchar)
  • DoCreation = registro de data e hora de quando a máquina mudou seu estado (data e hora)
  • MachineStateCode = novo estado da máquina, onde 99 = reinicializando, 0 = inicializando, 3 = erro, 1 = iniciando, 2 = funcionando e assim por diante (int)

Preciso criar uma nova coluna, vamos chamá-la de MachineStateCodeAdjusted, onde seu valor é igual a 3 se o MachineStateCode anterior for 3 e o MachineStateCode atual não for 2, caso contrário, deve ter o valor atual do MachineStateCode. (a próxima tabela é o que preciso)

Código de Máquina DoCreation CódigoDeEstadoDaMáquina MachineStateCodeAjustado
DM139 2024-04-03 00:32:17.377 99 99
DM139 2024-04-03 00:32:49.080 0 0
DM139 2024-04-03 01:51:14.427 99 99
DM139 2024-04-03 01:51:45.643 0 0
DM139 2024-04-03 06:07:38.357 3 3
DM139 2024-04-03 06:07:39.043 0 3
DM139 2024-04-03 06:23:37.433 100 3
DM139 2024-04-03 06:23:43.697 0 3
DM139 2024-04-03 06:24:46.153 1 3
DM139 2024-04-03 06:25:02.467 0 3
DM139 2024-04-03 06:46:50.410 100 3
DM139 2024-04-03 06:47:29.247 0 3
DM139 2024-04-03 06:47:46.397 100 3
DM139 2024-04-03 06:53:47.160 0 3
DM139 2024-04-03 06:59:41.633 1 3
DM139 2024-04-03 06:59:54.550 0 3
DM139 2024-04-03 07:00:03.203 1 3
DM139 2024-04-03 07:00:06.437 0 3
DM139 2024-04-03 07:00:14.247 1 3
DM139 2024-04-03 07:00:17.683 2 2
DM139 2024-04-03 07:00:18.153 1 1
DM139 2024-04-03 07:00:18.840 2 2
DM139 2024-04-03 07:00:26.860 1 1
DM139 2024-04-03 07:00:46.387 2 2

Usei a função LAG para obter o MachineStateCode anterior (e funciona), mas para funcionar como eu quero, preciso obter o MachineStateCodeAdjusted anterior, que não é acessível para a função LAG.

A consulta SQL que estou executando é esta:

   SELECT MachineCode
       , DoCreation
   , MachineStateCode
   , IIF(LAG(MachineStateCode, 1, MachineStateCode) OVER (ORDER BY DoCreation ASC) = 3 
  AND MachineStateCode<>2, 3, MachineStateCode)  AS MachineStateCodeAdjusted       
  FROM mch.MachineStateChanges

e o resultado que obtive me mostra claramente que não funciona como eu quero

Código de Máquina DoCreation CódigoDeEstadoDaMáquina MachineStateCodeAjustado
DM139 2024-04-03 00:32:17.377 99 99
DM139 2024-04-03 00:32:49.080 0 0
DM139 2024-04-03 01:51:14.427 99 99
DM139 2024-04-03 01:51:45.643 0 0
DM139 2024-04-03 06:07:38.357 3 3
DM139 2024-04-03 06:07:39.043 0 3
DM139 2024-04-03 06:23:37.433 100 100 ERRADOS
DM139 2024-04-03 06:23:43.697 0 0 ERRADO
DM139 2024-04-03 06:24:46.153 1 1 ERRADO

Também tentei com um CTE recursivo e funciona, mas é muito lento! A extração da consulta leva 4 minutos e 2 dias de trabalho, enquanto eu preciso extrair 1 ano!

Qual é a melhor (e rápida) abordagem para consertar isso?

sql
  • 3 3 respostas
  • 85 Views

3 respostas

  • Voted
  1. Best Answer
    The Impaler
    2025-04-23T01:34:13+08:002025-04-23T01:34:13+08:00

    Acho que sua explicação está incompleta. Você deveria ter indicado que, uma vez obtido um "erro" (3), todos os estados não importam, até que se obtenha um "funcionando" (2) novamente.

    Neste caso, trata-se de um problema de Lacunas e Ilhas. Você pode usar a solução tradicional:

    select z.*,
      case when f = 3 or (
              lag(MachineStateCode) 
                over(partition by MachineCode order by DoCreation) = 3
              and MachineStateCode <> 2
           )
           then 3 
           else MachineStateCode
      end as MachineStateCodeAdjusted
    from (
      select y.*,
        first_value(MachineStateCode) over(partition by g order by DoCreation) as f
      from (
        select x.*, sum(i) over(partition by MachineCode order by DoCreation) as g
        from (
          select t.*, case when MachineStateCode in (2, 3) then 1 else 0 end as i
          from MachineStateChanges t
        ) x
      ) y
    ) z
    

    Resultado:

     MachineCode  DoCreation                   MachineStateCode  i  g  f   MachineStateCodeAdjusted 
     ------------ ---------------------------- ----------------- -- -- --- ------------------------ 
     DM139        2024-04-03 00:32:17.3770000  99                0  0  99  99                       
     DM139        2024-04-03 00:32:49.0800000  0                 0  0  99  0                        
     DM139        2024-04-03 01:51:14.4270000  99                0  0  99  99                       
     DM139        2024-04-03 01:51:45.6430000  0                 0  0  99  0                        
     DM139        2024-04-03 06:07:38.3570000  3                 1  1  3   3                        
     DM139        2024-04-03 06:07:39.0430000  0                 0  1  3   3                        
     DM139        2024-04-03 06:23:37.4330000  100               0  1  3   3                        
     DM139        2024-04-03 06:23:43.6970000  0                 0  1  3   3                        
     DM139        2024-04-03 06:24:46.1530000  1                 0  1  3   3                        
     DM139        2024-04-03 06:25:02.4670000  0                 0  1  3   3                        
     DM139        2024-04-03 06:46:50.4100000  100               0  1  3   3                        
     DM139        2024-04-03 06:47:29.2470000  0                 0  1  3   3                        
     DM139        2024-04-03 06:47:46.3970000  100               0  1  3   3                        
     DM139        2024-04-03 06:53:47.1600000  0                 0  1  3   3                        
     DM139        2024-04-03 06:59:41.6330000  1                 0  1  3   3                        
     DM139        2024-04-03 06:59:54.5500000  0                 0  1  3   3                        
     DM139        2024-04-03 07:00:03.2030000  1                 0  1  3   3                        
     DM139        2024-04-03 07:00:06.4370000  0                 0  1  3   3                        
     DM139        2024-04-03 07:00:14.2470000  1                 0  1  3   3                        
     DM139        2024-04-03 07:00:17.6830000  2                 1  2  2   2                        
     DM139        2024-04-03 07:00:18.1530000  1                 0  2  2   1                        
     DM139        2024-04-03 07:00:18.8400000  2                 1  3  2   2                        
     DM139        2024-04-03 07:00:26.8600000  1                 0  3  2   1                        
     DM139        2024-04-03 07:00:46.3870000  2                 1  4  2   2                        
    

    Veja o exemplo em execução em db<>fiddle .

    • 2
  2. Jonas Metzler
    2025-04-23T02:11:07+08:002025-04-23T02:11:07+08:00

    Provavelmente você deseja aplicar as seguintes regras para a nova coluna MachineStateCodeAdjusted:

    • Se MachineStateCode for 2 ou 3, copie-o

    • Caso contrário, encontre a primeira linha antes da linha atual (classificada pela data) cujo MachineStateCode é 2 ou 3. Se esta linha anterior tiver o código 2 ou se nenhuma linha anterior puder ser encontrada, copie o MachineStateCode da linha atual; caso contrário, pegue 3.

    Uma maneira de implementar essa lógica é esta consulta:

    WITH sub AS (
        SELECT *, MachineStateCode AS MachineStateCodeAdjusted
        FROM yourtable
        WHERE MachineStateCode IN (2,3)
    )
    SELECT *
    FROM sub
    UNION ALL
    SELECT *,  
      COALESCE((SELECT TOP 1 CASE WHEN MachineStateCodeAdjusted = 3 THEN 3 
        ELSE y.MachineStateCode END FROM sub 
        WHERE sub.DoCreation <= y.DoCreation ORDER BY DoCreation DESC), y.MachineStateCode)
    FROM yourtable y
    WHERE MachineStateCode NOT IN (2,3)
    ORDER BY MachineCode, DoCreation;
    

    A ideia por trás:

    • Na consulta "sub" (renomeie-a se quiser e souber um nome melhor), todas as linhas com MachineStateCode 2 ou 3 serão selecionadas, seu MachineStateCode será simplesmente copiado como MachineStateCodeAdjusted.

    • A consulta principal seleciona todas as linhas cujo MachineStateCode não é 2 ou 3. Para essas linhas, será verificado se existem linhas anteriores (com uma data anterior) com MachineStateCode 2 ou 3.

    • Se tais linhas existirem, pegue a primeira (por data) antes da linha atual e verifique se essa linha tinha MachineStateCode 2 ou 3. Se fosse 2, copie o MachineStateCode, caso contrário, pegue 3 como MachineStateCodeAdjusted.

    • Se não existirem tais linhas, basta copiar o MachineStateCode como MachineStateCodeAdjusted.

    • Classifique todo o resultado por MachineCode e data

    Observe que talvez seja necessário estender a consulta se você quiser criar mais casos ou fazer com que a lógica e o resultado dependam do MachineCode atual (primeira coluna). Em seguida, você pode, por exemplo, adicionar uma condição para que o MachineCode na consulta principal e na subconsulta corresponda, se for o caso.

    Veja este db<>fiddle com seus dados de exemplo.

    • 1
  3. MatBailie
    2025-04-23T06:51:09+08:002025-04-23T06:51:09+08:00

    No SQL Server 2022 em diante (ou no Azure), você pode usar IGNORE NULLScom LAST_VALUE() (assim como o RedShift) .

    Isso significa que você pode ler facilmente o último código 2 ou 3 e usá-lo em uma expressão CASE.

    select
      *,
      case when last_23 = 3 then 3 else MachineStateCode END
    from
    (
      select
        *,
        LAST_VALUE(
          CASE WHEN MachineStateCode IN (2,3) THEN MachineStateCode END
        )
        IGNORE NULLS 
        OVER (
          PARTITION BY MachineCode
              ORDER BY DoCreation
        )
          AS last_23
      from
        MachineStateChanges
    )
      AS look_behind
    

    violino

    • 1

relate perguntas

  • Atualizando todas as linhas, exceto uma que tenha os mesmos valores em determinadas colunas

  • Existe uma maneira de inverter apenas os números quando eu retornar uma coluna sql? (hebraico)

  • SQL menor/maior comparação entre booleanos produz resultados inesperados

  • Como atualizar valores na tabela Postgres com base em uma correspondência em uma matriz

  • Como somar colunas no sql server

Sidebar

Stats

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

    Reformatar números, inserindo separadores em posições fixas

    • 6 respostas
  • Marko Smith

    Por que os conceitos do C++20 causam erros de restrição cíclica, enquanto o SFINAE antigo não?

    • 2 respostas
  • Marko Smith

    Problema com extensão desinstalada automaticamente do VScode (tema Material)

    • 2 respostas
  • Marko Smith

    Vue 3: Erro na criação "Identificador esperado, mas encontrado 'import'" [duplicado]

    • 1 respostas
  • Marko Smith

    Qual é o propósito de `enum class` com um tipo subjacente especificado, mas sem enumeradores?

    • 1 respostas
  • Marko Smith

    Como faço para corrigir um erro MODULE_NOT_FOUND para um módulo que não importei manualmente?

    • 6 respostas
  • Marko Smith

    `(expression, lvalue) = rvalue` é uma atribuição válida em C ou C++? Por que alguns compiladores aceitam/rejeitam isso?

    • 3 respostas
  • Marko Smith

    Um programa vazio que não faz nada em C++ precisa de um heap de 204 KB, mas não em C

    • 1 respostas
  • Marko Smith

    PowerBI atualmente quebrado com BigQuery: problema de driver Simba com atualização do Windows

    • 2 respostas
  • Marko Smith

    AdMob: MobileAds.initialize() - "java.lang.Integer não pode ser convertido em java.lang.String" para alguns dispositivos

    • 1 respostas
  • Martin Hope
    Fantastic Mr Fox Somente o tipo copiável não é aceito na implementação std::vector do MSVC 2025-04-23 06:40:49 +0800 CST
  • Martin Hope
    Howard Hinnant Encontre o próximo dia da semana usando o cronógrafo 2025-04-21 08:30:25 +0800 CST
  • Martin Hope
    Fedor O inicializador de membro do construtor pode incluir a inicialização de outro membro? 2025-04-15 01:01:44 +0800 CST
  • Martin Hope
    Petr Filipský Por que os conceitos do C++20 causam erros de restrição cíclica, enquanto o SFINAE antigo não? 2025-03-23 21:39:40 +0800 CST
  • Martin Hope
    Catskul O C++20 mudou para permitir a conversão de `type(&)[N]` de matriz de limites conhecidos para `type(&)[]` de matriz de limites desconhecidos? 2025-03-04 06:57:53 +0800 CST
  • Martin Hope
    Stefan Pochmann Como/por que {2,3,10} e {x,3,10} com x=2 são ordenados de forma diferente? 2025-01-13 23:24:07 +0800 CST
  • Martin Hope
    Chad Feller O ponto e vírgula agora é opcional em condicionais bash com [[ .. ]] na versão 5.2? 2024-10-21 05:50:33 +0800 CST
  • Martin Hope
    Wrench Por que um traço duplo (--) faz com que esta cláusula MariaDB seja avaliada como verdadeira? 2024-05-05 13:37:20 +0800 CST
  • Martin Hope
    Waket Zheng Por que `dict(id=1, **{'id': 2})` às vezes gera `KeyError: 'id'` em vez de um TypeError? 2024-05-04 14:19:19 +0800 CST
  • Martin Hope
    user924 AdMob: MobileAds.initialize() - "java.lang.Integer não pode ser convertido em java.lang.String" para alguns dispositivos 2024-03-20 03:12:31 +0800 CST

Hot tag

python javascript c++ c# java typescript sql reactjs html

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