Oracle присоединяется (слева, справа и т. Д.: S) - PullRequest
4 голосов
/ 09 октября 2008

Я знал, что stackoverflow поможет мне, кроме как узнать, что такое «любимый мультфильм программирования»: P

Это был принятый ответ: Билл Карвин

Спасибо всем за помощь (я бы хотел проголосовать за вас всех дважды)

Мой запрос закончился так (это настоящий)

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;

Теперь мне просто нужно объединиться с другими таблицами для удобочитаемого отчета.


ОРИГИНАЛЬНЫЙ ПОЧТА

Hello.

Я борюсь около 6 часов. теперь с запросом БД (мой давний враг)

У меня есть таблица данных с некоторыми полями, такими как:

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

Используется для отслеживания истории билета

Идентификатор : похож на идентификатор клиента (NAF0000001)

действие : fk того, где находится билет (новый, in_progress, отклонен, закрыт и т. Д.)

участник : fk того, кто посещает в этот момент билет

закрыто : дата завершения этой деятельности.

РЕДАКТИРОВАТЬ: Я должен был сказать "дата завершения", а не закрыто. Это дата, когда действие было завершено, необязательно, когда билет был закрыт.

Например, типичная история может быть такой:

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

И участник 1 = Джон, 2 = Скотт, 3 = Майк, 4 = Роб

и активностей 1 = новый, 2 = в процессе, 3 = ожидание для подтверждения, 4 = закрыто

и т.д.. И десятки другой не относящейся к делу информации.

Ну, моя проблема в следующем.

Мне удалось создать запрос, в котором я могу узнать, когда была открыта и закрыта заявка

это так:

 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

Но я не могу знать, какие билеты не закрыты и кто их посещает.

Пока у меня есть что-то вроде этого:

 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

Это дает мне всех, кто имеет старт (новый = 1), но не закрыт (закрыт = 4)

Но большая проблема здесь в том, что он печатает участника, который открыл билет, но мне нужен участник, который посещает его. Поэтому я добавляю в запрос действие "inprogress".

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

Но не все строки, находящиеся в "new", являются "inprogress", и с помощью этого запроса я отбрасываю все из них.

Мне нужно показать всех участников «inprogress», и если билет не «inprogress», он будет отображаться как пустой.

Что-то вроде

    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|

В этом случае

NA002, NA003 и NA004 находятся в «новом», поэтому ни один участник не отображается

В то время как

NA005 и NA006 являются "входящими (act = 2)", и их посещает грабитель (участник 4)

Итак, я помню, что было нечто, называемое левым внешним соединением или что-то подобное, но я никогда не понимаю этого. Что я хотел бы знать, так это как я могу получить идентификаторы, которые «inprogress» и «new» и которые не закрыты.

Возможно, небольшой отдых поможет мне очистить разум. Если кто-нибудь знает, как это сделать, я буду признателен.

Кстати, я пробовал:

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

Но дает мне тот же результат, что и предыдущий (сбросить только в "новые" записи)

Ответы [ 9 ]

3 голосов
/ 09 октября 2008

Попробуйте что-то вроде этого (я не проверял):

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;

Я думаю, что люди считают, что внешние соединения сложнее, чем они есть на самом деле. Например:

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

Возвращает все строки из A, независимо от того, есть ли соответствующие строки в B. Если ни одна строка в B не соответствует, все столбцы B. * обрабатываются как NULL в наборе результатов для этой строки A. быть выражением, которому должна удовлетворять строка в B, иначе она не будет включена в соединение. Таким образом, больше строк в A будут одиночными.

3 голосов
/ 09 октября 2008

Как правило, лучший способ написать это с EXISTS. Первый будет:

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

Этот способ позволяет вам выполнять поиск по ключу в performance.identifier, вместо того, чтобы создавать огромный список идентификаторов в (select identifier from performance where activity=4).

2 голосов
/ 09 октября 2008

Я думаю, что это должно сделать это.

Первая часть получает все новые записи, которые не закрыты и не выполняются. Вторая часть получает все в процессе записи. Затем мы соединяем их вместе, мы также можем отсортировать по идентификатору, обернув «SELECT * FROM» вокруг этого запроса.

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); 
1 голос
/ 09 октября 2008

Как насчет этого:

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)

Внутренний запрос дает самую последнюю активность для каждого тикета и соответствующего участника. Внешний запрос фильтрует это до тех, где действие является «новым» или «в процессе».

Мне нравятся функции DENSE_RANK.

1 голос
/ 09 октября 2008

Я бы предположил, что вам нужна самая ранняя запись (предположительно, но не обязательно та, у которой активность = 1) и самая последняя запись (независимо от номера активности). Если активность самой последней записи 4, то заявка закрывается. в противном случае участник является текущим владельцем билета. Существует потенциальная ошибка, вызванная простым сопоставлением активности = 4, если билет может быть повторно открыт.

На самом деле, исходя из вашего примера, вам может даже не понадобиться самая ранняя запись. Как насчет следующего:

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
            )
;
0 голосов
/ 09 октября 2008

Просто быстрая идея, на которой могли бы основываться другие (не проверено, но я надеюсь, что идея встречается):

Сначала выберите все еще не закрытые действия (опубликованные другими):

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

Затем вы можете добавить человека, посещающего мероприятие, добавив подзапрос в предложении 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)

Если для этого идентификатора нет записи действия 3, подзапрос возвращает значение null, что именно то, что нам нужно.

Надеюсь, это поможет - пожалуйста, расширьте при необходимости.

0 голосов
/ 09 октября 2008

Может быть, вы можете использовать этот тип запроса в качестве отправной точки.

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

Идея состоит в том, чтобы сериализовать вашу таблицу из строки в поле и создать представление на ее основе. Вы можете создать отчет на основе этого представления.

С уважением,

0 голосов
/ 09 октября 2008

Какие билеты не закрыты:

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

Билеты, которые посещают:

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

Неразглашенные билеты, в которых участвует участник:

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
0 голосов
/ 09 октября 2008

Во-первых, у вас могут возникнуть проблемы с дизайном, если у вас может быть клиент с несколькими открытыми билетами одновременно. В идеале у вас должен быть ticket_id, а затем вы можете выполнить запрос Энди, используя ticket_id вместо идентификатора.

...