Pregunta

Sabía que stackoverflow me ayudaría, aparte de saber cuál es el "dibujo animado de programación favorito". : P

Esta fue la respuesta aceptada por: Bill Karwin

Gracias a todos por la ayuda (me gustaría votarlos a todos)

Mi consulta terminó así (esta es la real)

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;

Ahora solo tengo que unirme con las otras tablas para obtener un informe legible para humanos.


PUBLICACIÓN ORIGINAL

Hola.

Estoy luchando durante unas 6 horas. ahora con una consulta de base de datos (mi antiguo enemigo)

Tengo una tabla de datos con algunos campos como:

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

Se utiliza para realizar un seguimiento del historial de tickets

Identificador : es una identificación de cliente como (NAF0000001)

actividad : es un lugar donde se encuentra el ticket (nuevo, en progreso, rechazado, cerrado, etc.)

participante : es una persona que está asistiendo en ese momento al boleto

fecha de cierre : es la fecha en que finalizó esa actividad.

EDITAR: debería haber dicho " completedate " en lugar de cerrar la fecha. Esta es la fecha en que se completó la actividad, no es necesario cuando se cerró el ticket.

Por ejemplo, un historial típico puede ser así:

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|
-------------------------------------------

Y el participante 1 = jonh, 2 = scott, 3 = mike, 4 = rob

y actividades 1 = nuevo, 2 = en progreso, 3 = espera para aprobación, 4 = cerrado

etc. Y decenas de otra información irrelevante.

Bueno, mi problema es el siguiente.

He logrado crear una consulta donde puedo saber cuándo se abrió y cerró un ticket

es así:

 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

Pero no puedo saber qué boletos no están cerrados y quién los atiende.

Hasta ahora tengo algo como esto:

 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

Es decir, dame todos los que tienen un comienzo (nuevo = 1) pero no están cerrados (cerrado = 4)

Pero el gran problema aquí es que imprime al participante que abrió el boleto, pero necesito al participante que lo atiende. Entonces agrego el " en progreso " actividad a la 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..

Pero no todas las filas que están en " new " están " en progreso " y con esa consulta los elimino a todos.

Lo que necesito es mostrar todos los " en progreso " participante y si el ticket no está "en progreso", se mostrará como vacío.

Algo así

    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|

En este caso

NA002, NA003 y NA004 están en "nuevo", por lo que no se muestra ningún participante

Mientras

NA005 y NA006 están siendo "en progreso (act = 2)" y están siendo atendidos por rob (participante 4)

Así que recuerdo que había una cosa llamada combinación externa izquierda o algo así, pero nunca lo entiendo. Lo que me gustaría saber es cómo puedo obtener los identificadores que están en progreso. y "nuevo" y que no están cerrados.

Probablemente descansar un poco me ayudaría a aclarar mi mente. Si alguien sabe cómo hacerlo, lo agradeceré.

Por cierto, he intentado:

 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..

Pero me da el mismo resultado que el anterior (suelte el único en " nuevos " registros)

¿Fue útil?

Solución

Pruebe algo como esto (no lo he probado):

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;

Creo que la gente cree que las uniones externas son más difíciles de lo que realmente son. Por ejemplo:

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

Esto devuelve todas las filas de A, ya sea que haya o no filas coincidentes en B. Si no hay filas en B coincidentes, trate todas las columnas B. * como NULL en el conjunto de resultados para esa fila de A. La condición de unión puede ser una expresión que la fila en B debe satisfacer, o de lo contrario no se incluye en la unión. Entonces, más filas en A serán solo.

Otros consejos

Normalmente, la mejor manera de escribirlos es con EXISTS. El primero sería:

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

De esta forma, puede realizar una búsqueda con clave en performance.identifier, en lugar de tener que crear una lista masiva de identificadores en (seleccione el identificador de performance donde activity = 4) .

Creo que esto debería hacerlo.

La primera parte obtiene todos los registros que son nuevos, no están cerrados y no están en progreso. La segunda parte obtiene todos los registros de progreso. Luego los unimos, también podemos ordenar por identificador colocando un 'SELECCIONAR * DESDE' alrededor de esta 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); 

Sugeriría que lo que desea es el registro más antiguo (presumiblemente, pero no necesariamente el que tiene actividad = 1) y el registro más reciente (independientemente del número de actividad). Si la actividad del registro más reciente es 4, el ticket está cerrado. de lo contrario, el participante es el titular actual del boleto. Existe un posible error introducido simplemente haciendo coincidir la actividad = 4 si el ticket se puede volver a abrir.

En realidad, según su ejemplo, es posible que ni siquiera necesite el registro más antiguo. ¿Qué tal lo siguiente:

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
            )
;

¿Qué tal esto?

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)

La consulta interna proporciona la actividad más reciente para cada ticket y su participante correspondiente. La consulta externa filtra esto a aquellos donde la actividad es " nueva " o "en progreso".

Me encantan las funciones DENSE_RANK.

En primer lugar, puede tener un problema de diseño si puede tener un cliente con varios tickets abiertos al mismo tiempo. Idealmente, debe tener un ticket_id, y luego puede realizar la consulta de Andy utilizando ticket_id en lugar de un identificador.

Qué entradas no están cerradas:

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

Entradas a las que se asiste:

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

Entradas no cerradas, con la asistencia de los participantes:

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

Puede ser que pueda usar este tipo de consulta como punto 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

La idea es serializar su tabla de fila en campo y crear una vista basada en ella. Puede crear un informe basado en esta vista.

Saludos,

Solo una idea rápida en la que otros podrían construir (sin probar, pero espero que la idea se presente):

Primero, seleccione todas las actividades aún no cerradas (según lo publicado por otros):

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

Luego, puede agregar a la persona que asiste a la actividad agregando una subconsulta en la cláusula select:

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)

Si no hay ningún registro de actividad 3 para esta identificación, la subconsulta devuelve nulo, que es exactamente lo que necesitamos.

Espero que esto ayude. Expanda si es necesario.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top