Oracle加入(左外,右等等:S)

时间:2008-10-08 23:19:45

标签: sql oracle join left-join

我知道stackoverflow会帮助我,除了知道什么是“最喜欢的编程卡通”:P

这是接受的答案: Bill Karwin

感谢大家的帮助(我想双倍投票给你们)

我的查询最终结果如此(这是真实的)

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;

现在我只需要与其他表一起加入人类可读的报告。

<小时/> 原始帖子

您好。

我挣扎了大约6个小时。现在有一个数据库查询(我的长期克星)

我有一个包含以下字段的数据表:

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

用于跟踪故障单的历史记录

标识符:是一个客户ID,如(NAF0000001)

活动:是票证所在地的fk(新的,in_progress,拒绝,关闭等)

参与者:当时正在参加门票的人员

关闭:是该活动结束的日期。

编辑:我应该说“完成日期”而不是关闭。这是活动完成的日期,当票证关闭时不需要。

例如,典型的历史可能是这样的:

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 = jonh,2 = scott,3 =迈克,4 =抢劫

和活动1 =新的,2 =进行中,3 = waitingforapproval,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正在“inprgress(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 个答案:

答案 0 :(得分:3)

通常,更好的方法是使用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)中构建大量标识符列表。

答案 1 :(得分:3)

尝试这样的事情(我还没有测试过):

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。连接条件可以是B中的行必须满足的表达式,否则它不包含在连接中。因此,A中的更多行将是独奏。

答案 2 :(得分:2)

我认为应该这样做。

第一部分获取所有新记录,未关闭且未进行记录。第二部分获取所有正在进行的记录。然后我们将它们连接在一起,我们也可以通过在此查询周围包装“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); 

答案 3 :(得分:1)

我建议你想要的是最早的记录(可能,但不一定是活动= 1的记录)和最近的记录(不论活动编号)。如果最近记录的活动为4,则票证将关闭。否则,参与者是票证的当前持有者。如果可以重新打开故障单,只需在activity = 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
            )
;

答案 4 :(得分:1)

这个怎么样:

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功能。

答案 5 :(得分:0)

首先,如果您的客户可以同时打开多张票,则可能会遇到设计问题。理想情况下,您应该拥有ticket_id,然后您可以使用ticket_id而不是标识符来执行Andy的查询。

答案 6 :(得分:0)

什么门票没有关闭:

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

答案 7 :(得分:0)

可能您可以使用此类查询作为起点。

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

我们的想法是将您的表从一行序列化为字段,并基于它创建一个视图。 您可以根据此视图创建报告。

此致

答案 8 :(得分:0)

只是快速了解其他人可能会建立的(未经测试,但我希望这个想法能够实现):

首先,选择所有尚未结束的活动(由其他人发布):

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)

如果此id没有活动3记录,则子查询返回null,这正是我们所需要的。

希望这会有所帮助 - 如有必要请扩展。