Pergunta

Eu sabia que o Stackoverflow me ajudaria além de saber qual é o "desenho de programação favorito": P

Esta foi a resposta aceita por:Bill Karwin

Obrigado a todos pela ajuda (eu gostaria de votar em dobro de todos vocês)

Minha consulta acabou assim (esta é a verdadeira)

SELECT 
    accepted.folio,
    COALESCE( inprog.activityin, accepted.activityin ) as activityin,
    inprog.participantin,
    accepted.completiondate 
FROM performance accepted
    LEFT OUTER JOIN performance inprog 
        ON( accepted.folio = inprog.folio 
            AND inprog.ACTIVITYIN 
            IN ( 4, 435 )                    -- both are ids for inprogress
            AND inprog.PARTICIPANTIN != 1  ) -- Ignore the "bot" participant
    LEFT OUTER JOIN performance closed
        ON( accepted.folio = closed.folio 
            AND closed.ACTIVITYIN IN ( 10,436, 4, 430  ) )  -- all these are closed or cancelled
WHERE accepted.ACTIVITYIN IN ( 3, 429 )      --- both are id for new 
AND accepted.folio IS NOT NULL
AND closed.folio IS NULL;

Agora eu só tenho que me juntar às outras tabelas para um relatório legível por humanos.


Postagem original

Olá.

Estou lutando por cerca de 6 horas. Agora com uma consulta de banco de dados (meu inimigo de longa data)

Eu tenho uma tabela de dados com alguns campos como:

table performance( 
     identifier varchar, 
     activity    number, 
     participant number, 
     closedate   date, 
)

É usado para acompanhar a história do tíquete

Identificador: é um ID de cliente como (NAF0000001)

atividade: é um FK de onde o bilhete está (novo, in_progress, rejeitado, fechado, etc)

participante: é um FK de quem está participando naquele momento o bilhete

data de encerramento: é a data em que essa atividade terminou.

EDITAR: Eu deveria ter dito "conclusão" em vez de fechado. Esta é a data em que a atividade foi concluída, não é necessária quando o bilhete foi fechado.

Por exemplo, uma história típica pode ser assim:

identifier|activity|participant|closedate
-------------------------------------------
NA00000001|       1|          1|2008/10/08 15:00|
-------------------------------------------
NA00000001|       2|          2|2008/10/08 15:20|
-------------------------------------------
NA00000001|       3|          2|2008/10/08 15:40|
-------------------------------------------
NA00000001|       4|         4|2008/10/08 17:05|
-------------------------------------------

E participante 1 = Jonh, 2 = Scott, 3 = Mike, 4 = Rob

e Activties 1 = novo, 2 = inprogress, 3 = WaitingForAproval, 4 = fechado

etc. e dezenas de outras informações irrelevantes.

Bem, meu problema é o seguinte.

Consegui criar uma consulta onde posso saber quando um ingresso foi aberto e fechado

é assim:

 select 
     a.identifier,
     a.participant,
     a.closedate as start,
     b.closedate as finish      
from 
    performance a,
    performance b
where
    a.activity = 1 -- new
    and b.activity = 4 -- closed
    and a.identifier = b.identifier

Mas não sei saber quais são os ingressos não Fechado e quem os está atendendo.

Até agora eu tenho algo assim:

 select 
     a.identifier,
     a.participant,
     a.closedate as start
from 
    performance a        
where
    a.activity = 1 -- new
    and a.identifier not in ( select identifier from performance where activity = 4 ) --closed

Isso é me dê todos os que têm um começo (novo = 1), mas não estão fechados (fechados = 4)

Mas o grande problema aqui é que ele imprime o participante que abriu o bilhete, mas preciso do participante que o está participando. Então, eu adiciono a atividade "inprogressista" à consulta.

 select 
     a.identifier,
     a.participant,
     a.closedate as start
from 
    performance a,
    performance b        
where
    a.activity = 1 -- new        
    and a.identifier not in ( select identifier from performance where activity = 4 ) --closed
    and b.identifier = a.identifier
    and b.activity = 2  -- inprogress..

Mas nem todas as linhas que estão em "novos" estão "emprogressos" e, com essa consulta, deixo todos eles.

O que eu preciso é mostrar todo o participante "inprogressista" e, se o ingresso não estiver "inpropreente", será exibido como vazio.

Algo como

    identifier|activity|participant|closedate
-------------------------------------------
NA00000002|       1|           |2008/10/08 15:00|
-------------------------------------------
NA00000003|       1|           |2008/10/08 15:20|
-------------------------------------------
NA00000004|       1|           |2008/10/08 15:40|
-------------------------------------------
NA00000005|       2|          4|2008/10/08 15:40|
-------------------------------------------
NA00000006|       2|          4|2008/10/08 15:40|

Nesse caso

NA002, NA003 e NA004 estão em "novo", então nenhum participante é mostrado

Enquanto

NA005 e NA006 estão sendo "inprogressistas (ACT = 2)" e estão sendo atendidos por Rob (participante 4)

Então, lembro que havia essa coisa chamada de junta externa esquerda ou algo assim, mas eu nunca a entendo. O que eu gostaria de saber é como posso buscar os identificadores que estão "emprogressos" e "novos" e que não estão fechados.

Provavelmente descansar um pouco me ajudaria a esclarecer minha mente. Se alguém souber fazer isso, eu apreciarei.

A propósito, eu tentei:

 select 
     a.identifier,
     a.participant,
     a.closedate as start
from 
    performance a
    left outer join
    performance b  
    on      
    b.identifier = a.identifier
where
    a.activity = 1 -- new        
    and a.identifier not in ( select identifier from performance where activity = 4 ) --closed
    and b.activity = 2  -- inprogress..

Mas me dá o mesmo resultado que o anterior (solte o único nos registros "novos")

Foi útil?

Solução

Tente algo assim (eu não testei):

SELECT p_new.identifier, COALESCE(p_inprog.activity, p_new.activity) AS activity,
  p_inprog.participant, COALESCE(p_inprog.closedate, p_new.closedate) AS closedate
FROM performance p_new
  LEFT OUTER JOIN performance p_inprog 
    ON (p_new.identifier = p_inprog.identifier AND p_inprog.activity = 2)
  LEFT OUTER JOIN performance p_closed 
    ON (p_new.identifier = p_closed.identifier AND p_closed.activity = 4)
WHERE p_new.activity = 1
  AND p_closed.identifier IS NULL;

Eu acho que as pessoas acreditam que as juntas externas são mais difíceis do que realmente são. Por exemplo:

A LEFT OUTER JOIN B ON (...condition...)

Isso retorna todas as linhas de A, se existem linhas correspondentes ou não em B. Se não houver linhas na partida B, trate todas as colunas B.* como nulo no conjunto de resultados para essa linha de A. A condição de junção pode ser uma expressão que a linha em B deve satisfazer, ou então não está incluída na junção. Portanto, mais linhas em um será solo.

Outras dicas

Normalmente, a melhor maneira de escrever isso é existe. O primeiro seria:

select * from performance p1
where not exists 
    ( select * from performance p2 
      where p2.identifier = p1.identifier and p2.activity = 4 )

Dessa forma, você permite fazer uma pesquisa com chave no desempenho. (select identifier from performance where activity=4).

Eu acho que isso deveria fazer isso.

A primeira parte obtém todos os registros que são novos, não fechados e não em andamento. A segunda parte coloca todos os registros em andamento. Em seguida, juntamos eles, também podemos classificar por identificador envolvendo um 'select * de' em torno desta consulta.

select 
  a.identifier,
  a.participant,
  a.closedate as start
from 
  performance a
where
  a.activity = 1
  and not exists ( select identifier 
                   from performance b 
                   where b.activity = 4 
                   and b.identifier = a.identifier) 
  and not exists ( select identifier 
                   from performance c 
                   where c.activity = 2 
                   and c.identifier = a.identifier) 
UNION ALL
select 
  a.identifier,
  a.participant,
  a.closedate as start
from 
  performance a
where
  a.activity = 2
  and not exists ( select identifier 
                   from performance b 
                   where b.activity = 4 
                   and b.identifier = a.identifier); 

Eu sugeriria que o que você deseja é o registro mais antigo (presumivelmente, mas não necessariamente aquele com atividade = 1) e o registro mais recente (independentemente do número da atividade). Se a atividade do registro mais recente for 4, o ingresso será fechado. Caso contrário, o participante é o atual titular do ticket. Existe um bug potencial introduzido apenas correspondendo à atividade = 4 se o ticket puder ser reaberto.

Na verdade, com base no seu exemplo, você pode nem precisar do registro mais antigo. Que tal o seguinte:

SELECT
        identifier,
        activity,
        participant,
        closedate
    FROM
        performance a
    WHERE
        (a.identifier, a.closedate) in
            (select b.identifier, max(b.closedate)
                from performance b
                group by b.identifier
            )
;

Que tal agora:

SELECT * FROM (
  SELECT identifier,
         MAX(activity) activity,
         MAX(participant) KEEP (DENSE_RANK LAST ORDER BY activity)
    FROM performance
    GROUP BY identifier
)
WHERE activity in (1,2)

A consulta interna fornece a atividade mais recente para cada ingresso e seu participante correspondente. A consulta externa o filtra para aqueles em que a atividade é "nova" ou "em andamento".

Eu amo as funções dense_rank.

Em primeiro lugar, você pode ter um problema de design se puder ter um cliente com vários ingressos abertos ao mesmo tempo. Idealmente, você deve ter um ticket_id e, em seguida, pode executar a consulta de Andy usando o ticket_id em vez do identificador.

Quais ingressos não estão fechados:

select identifier as closed_identifier 
  from performance where identifier not exists
  (select identifier from performance where activity=4)

Ingressos que estão sendo atendidos:

select identifier as inprogress_identifier, participant performance 
  from performance where activity=2

Os ingressos não foram atendidos, com o participante disso está sendo atendido:

select * from 
  (select identifier as notclosed_identifier 
    from performance where identifier not exists
    (select identifier from performance where activity=4)) closed 
left join 
  (select identifier as inprogress_identifier, participant performance 
    from performance where activity=2) attended 
on notclosed_identifier=inprogress_identifier

Pode ser que você possa usar esse tipo de consulta como ponto de partida.

select x.identifier, 
       max(x.p_1) as new_participant, max(x.c_1) as new_date,
       max(x.p_2) as inprogress_participant, max(x.c_2) as inprogress_date,
       max(x.p_3) as approval_participant, max(x.c_3) as approval_date,
       max(x.p_4) as closing_participant, max(x.c_4) as closing_date
  from (
        select a.identifier, 
               decode (activity, 1, participant, null) as p_1,  decode (activity, 1, closedate, null) as c_1,
               decode (activity, 2, participant, null) as p_2,  decode (activity, 2, closedate, null) as c_2,
               decode (activity, 3, participant, null) as p_3,  decode (activity, 3, closedate, null) as c_3,
               decode (activity, 4, participant, null) as p_4,  decode (activity, 4, closedate, null) as c_4
          from performance a
        ) x
 group by x.identifier

A idéia é serializar sua tabela da linha para o campo e criar uma visualização com base nela. Você pode criar relatório com base nessa visualização.

Cumprimentos,

Apenas uma ideia rápida que outros possam desenvolver (não testados, mas espero que a ideia apareça):

Primeiro, selecione todas as atividades ainda não fechadas (conforme publicado por outras pessoas):

select id
from performance p1 where identifier not exists
  (select * from performance p2 where activity=4 and p1.id=p2.id)

Em seguida, você pode adicionar a pessoa que compareceu à atividade adicionando uma subconsulta na cláusula selecionada:

select id,
 (select participant 
  from performance p3 
  where p3.activity=3 and p1.id=p2.id)
from performance p1 where identifier not exists
  (select * from performance p2 where activity=4 and p1.id=p2.id)

Se não houver registro da Atividade 3 para este ID, o subconstorial retorna nulo, o que é exatamente o que precisamos.

Espero que isso ajude - por favor, expanda se necessário.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top