2012-03-11 6 views
1

У меня есть большой стол с инцидентами. При этом я хочу прикрепить значения из «Инцидентов» и «Комментарии к инцидентам». Я использовал левое внешнее соединение, так как может быть или не быть никаких комментариев или вложений для Инцидента.
Теперь, когда я использую несколько внешних соединений, я получаю дублированные строки.Несколько результатов левого внешнего соединения в дублированных строках

Существует значение incidentID, что является общим для всех таблиц

INC1 ATT1 COMMENT1 
INC1 ATT1 COMMENT2 
INC1 ATT2 COMMENT1 
INC1 ATT2 COMMENT2 

Но на самом деле вывод должен быть:

INC1 ATT1 COMMENT1 
INC1 ATT2 COMMENT2 

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

select inc,att.attname,comment.commenttext 
from inc 
     left outer join att inc.incidentID=att.incidentID 
     left outer join comment inc.incidentID=comment .incidentID 

Возможно ли это?

+0

Тангенциальное: Ваш запрос отсутствует пару 'on's – bernie

+2

@MikeRyan: Re:«Там нет очевидных причин, почему это было бы сделайте это »: я думаю, вы должны недопонимать что-то в этом вопросе, потому что то, что он описывает, является именно нормальным поведением' JOIN'. Фактически есть декартово произведение между 'att' и' comment', так как ничто в любом 'ON' или' WHERE' не ограничивает отношения между ними. – ruakh

+0

6_2010/01/07 имеет 4 вложения и 7 комментариев, следовательно, он возвращает 28 строк, в то время как эффективно он не должен превышать 7 строк. – user1262986

ответ

2

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

TEST DATA:

SQL> CREATE TABLE inc (incidentid NUMBER, incname VARCHAR2(20)); 

Table created. 

SQL> INSERT INTO inc VALUES (1,'incident 1'); 

1 row created. 

SQL> INSERT INTO inc VALUES (2,'incident 2'); 

1 row created. 

SQL> CREATE TABLE att (att_id NUMBER, incidentid NUMBER, attname VARCHAR2(20)); 

Table created. 

SQL> INSERT INTO att VALUES (101, 1, 'attachment 1'); 

1 row created. 

SQL> INSERT INTO att VALUES (102, 1, 'attachment 2'); 

1 row created. 

SQL> INSERT INTO att VALUES (103, 1, 'attachment 3'); 

1 row created. 

SQL> INSERT INTO att VALUES (104, 1, 'attachment 4'); 

1 row created. 

SQL> INSERT INTO att VALUES (105, 1, 'attachment 5'); 

1 row created. 

SQL> INSERT INTO att VALUES (110, 2, 'attachment A'); 

1 row created. 

SQL> INSERT INTO att VALUES (111, 2, 'attachment B'); 

1 row created. 

SQL> INSERT INTO att VALUES (112, 2, 'attachment C'); 

1 row created. 

SQL> CREATE TABLE comments (comment_id NUMBER, incidentid NUMBER, commenttext VARCHAR2(20)); 

Table created. 

SQL> INSERT INTO comments VALUES (201, 1, 'first comment'); 

1 row created. 

SQL> INSERT INTO comments VALUES (202, 1, 'second comment'); 

1 row created. 

SQL> INSERT INTO comments VALUES (203, 1, 'third comment'); 

1 row created. 

ПРЕДЛОЖЕННЫЙ QUERY:

SQL> WITH a AS (
    2  SELECT att.incidentid 
    3  ,  COUNT(att.att_id) rows_per_incident 
    4  FROM att 
    5  GROUP BY att.incidentid 
    6  UNION ALL 
    7  SELECT comments.incidentid 
    8  ,  COUNT(comments.comment_id) rows_per_incident 
    9  FROM comments 
10  GROUP BY comments.incidentid 
11 ) 
12 , b AS (
13  SELECT inc.incidentid 
14  ,  inc.incname 
15  ,  ROW_NUMBER() 
16    OVER (PARTITION BY inc.incidentid ORDER BY NULL) row_num 
17  FROM inc 
18  ,  (SELECT ROWNUM multiplier FROM DUAL CONNECT BY LEVEL <= (SELECT MAX(rows_per_incident) FROM a)) 
19 ) 
20 , c AS (
21  SELECT att.att_id 
22  ,  att.incidentid 
23  ,  att.attname 
24  ,  ROW_NUMBER() 
25    OVER (PARTITION BY att.incidentid ORDER BY att.att_id) att_rn 
26  FROM att 
27 ) 
28 , d AS (
29  SELECT comments.comment_id 
30  ,  comments.incidentid 
31  ,  comments.commenttext 
32  ,  ROW_NUMBER() 
33    OVER (PARTITION BY comments.incidentid ORDER BY comments.comment_id) comm_rn 
34  FROM comments 
35 ) 
36 , e AS (
37  SELECT c.incidentid 
38  ,  c.att_id 
39  ,  c.attname 
40  ,  c.att_rn  rn 
41  ,  d.comment_id 
42  ,  d.commenttext 
43  FROM c 
44  ,  d 
45  WHERE c.incidentid = d.incidentid (+) 
46  AND  c.att_rn  = d.comm_rn (+) 
47  UNION ALL 
48  SELECT TO_NUMBER(NULL) incidentid 
49  ,  TO_NUMBER(NULL) att_id 
50  ,  NULL   attname 
51  ,  d.comm_rn  rn 
52  ,  d.comment_id 
53  ,  d.commenttext 
54  FROM d 
55  WHERE NOT EXISTS (SELECT NULL 
56       FROM c 
57       WHERE c.incidentid = d.incidentid 
58       AND  c.att_rn  = d.comm_rn) 
59 ) 
60 , f AS (
61 SELECT b.incidentid 
62 ,  b.incname 
63 ,  b.row_num 
64 ,  e.att_id 
65 ,  e.attname 
66 ,  e.comment_id 
67 ,  e.commenttext 
68 FROM b 
69  LEFT OUTER JOIN e ON b.incidentid = e.incidentid 
70      AND b.row_num = e.rn 
71 ) 
72 SELECT f.incidentid 
73 ,  f.incname 
74 ,  f.att_id 
75 ,  f.attname 
76 ,  f.comment_id 
77 ,  f.commenttext 
78 FROM f 
79 WHERE NOT (f.att_id IS NULL AND f.comment_id IS NULL) 
80 ORDER BY f.incidentid 
81 ,  f.row_num 
82 ; 

INCIDENTID INCNAME     ATT_ID ATTNAME    COMMENT_ID COMMENTTEXT 
---------- -------------------- ---------- -------------------- ---------- -------------------- 
     1 incident 1     101 attachment 1    201 first comment 
     1 incident 1     102 attachment 2    202 second comment 
     1 incident 1     103 attachment 3    203 third comment 
     1 incident 1     104 attachment 4 
     1 incident 1     105 attachment 5 
     2 incident 2     110 attachment A 
     2 incident 2     111 attachment B 
     2 incident 2     112 attachment C 

8 rows selected. 

SQL> 
Смежные вопросы