2012-03-11 85 views
1

我有一個大表有事件。有了這個我想附上來自事件附件和事件評論的值。我已經使用了Left外部連接,因爲對於事件可能有也可能沒有任何評論或附件。
現在,當我使用多個外部連接時,我得到了重複的行。多個左外連接導致重複的行

有一個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 2012-03-11 23:48:40

+2

@MikeRyan的:回覆:「有沒有明顯的理由爲什麼它會這樣做「:我認爲你必須誤解問題中的某些內容,因爲它描述的正是」JOIN「的正常行爲。 'att'和'comment'之間有笛卡兒積,因爲任何'ON'或'WHERE'子句都沒有限制它們之間的關係。 – ruakh 2012-03-12 00:02:32

+0

6_2010/01/07有4個附件和7條評論,因此它返回28行,而實際上它應該不超過7行 – user1262986 2012-03-12 00:20:24

回答

2

到目前爲止,我從你的回答中拿掉的一件事是,對於一個給定的事件,它的附件和它的評論之間沒有直接的關係。 如果我理解正確,您希望將事件視爲附件和註釋的簡單「容器」,並且您只需要列出每個附件和註釋。哪個 附件碰巧出現在同一行中,因爲特定註釋對您而言是偶然的。

測試數據:

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>