2012-11-24 28 views
11

Sử dụng CONNECT BY LEVEL dường như trả về quá nhiều hàng khi được thực hiện trên một bảng. Logic đằng sau những gì đang xảy ra?Tại sao CONNECT BY LEVEL trên một bảng trả lại hàng bổ sung?

Giả sử bảng sau:

create table a (id number); 

insert into a values (1); 
insert into a values (2); 
insert into a values (3); 

Truy vấn này trả về 12 dòng (SQL Fiddle).

select id, level as lvl 
    from a 
connect by level <= 2 
    order by id, level 

Một hàng cho mỗi trong bảng A với giá trị của cột LVL là 1 và ba cho mỗi trong bảng A nơi LVL cột là 2, ví dụ:

 
ID | LVL 
---+----- 
1 | 1 
1 | 2 
1 | 2 
1 | 2 
2 | 1 
2 | 2 
2 | 2 
2 | 2 
3 | 1 
3 | 2 
3 | 2 
3 | 2 

Nó tương đương với này truy vấn, trả về cùng một kết quả.

select id, level as lvl 
    from dual 
    cross join a 
connect by level <= 2 
    order by id, level 

Tôi không hiểu tại sao các truy vấn này trả về 12 hàng hoặc tại sao có ba hàng LVL là 2 và chỉ có LVL là 1 cho mỗi giá trị của cột ID.

Tăng số lượng các cấp được "kết nối" với 3 returns 13 rows cho mỗi giá trị của ID. 1 nơi LVL là 1, 3 nơi LVL là 2 và 9 nơi LVL là 3. Điều này dường như gợi ý rằng các hàng trả về là số hàng trong bảng A với công suất của giá trị LVL trừ 1.

I sẽ có dù rằng các truy vấn này sẽ được giống như những điều sau đây, trong đó trả 6 hàng

select id, lvl 
    from (select level as lvl 
      from dual 
     connect by level <= 2 
       ) 
cross join a 
order by id, lvl 

các documentation không phải là đặc biệt rõ ràng, đối với tôi, trong việc giải thích những gì sẽ xảy ra. Điều gì đang xảy ra với các quyền hạn này và tại sao hai truy vấn đầu tiên lại không giống như các truy vấn thứ ba?

+0

Liệu chúng ta có một cái gì đó trong MySQL 5, tương đương với điều này? – abhijitcaps

Trả lời

9

Trong truy vấn đầu tiên, bạn kết nối chỉ bằng cấp. Vì vậy, nếu mức < = 1, bạn nhận được mỗi bản ghi 1 lần. Nếu mức < = 2, sau đó bạn nhận được mỗi cấp 1 thời gian (cho cấp 1) + N lần (trong đó N là số lượng bản ghi trong bảng).Nó giống như bạn đang tham gia chéo, bởi vì bạn chỉ cần chọn tất cả các bản ghi từ bảng cho đến khi đạt đến mức, mà không có các điều kiện khác để hạn chế kết quả. Đối với mức < = 3, điều này được thực hiện lại cho mỗi kết quả.

Vì vậy, trong 3 hồ sơ:

  • Lvl 1: 3 kỷ lục (tất cả có mức độ 1)
  • Lvl 2: 3 hồ sơ có mức 1 + 3 * 3 hồ sơ có mức 2 = 12
  • Lvl 3: 3 + 3 * 3 + 3 * 3 * 3 = 39 (thực sự là 13 bản ghi).
  • Lvl 4: bắt đầu thấy mẫu? :)

Nó không thực sự là sự tham gia chéo. Một phép nối chéo sẽ chỉ trả về các bản ghi có cấp 2 trong kết quả truy vấn này, trong khi với kết nối này, bạn nhận được các bản ghi có cấp 1 cũng như các bản ghi có cấp 2, do đó dẫn đến 3 + 3 * 3 thay vì chỉ Bản ghi 3 * 3.

1

bạn đang so sánh táo với cam khi so sánh truy vấn cuối cùng với những người khác vì LEVEL được phân tách trong đó thành bảng kép 1 hàng.

cho phép xem xét truy vấn này:

select id, level as lvl 
    from a 
connect by level <= 2 
    order by id, level 

những gì được nói là, bắt đầu với các thiết lập bảng (chọn * Từ a). sau đó, đối với mỗi hàng trả về, hãy kết nối hàng này với hàng trước. vì bạn chưa xác định một kết nối trong kết nối, điều này có hiệu lực khi tham gia Descartes, vì vậy khi bạn có 3 hàng (1,2,3) 1 tham gia vào 2, 1-> 3, 2-> 1, 2 -> 3, 3-> 1 và 3-> 2 và họ cũng tham gia với bản thân 1-> 1,2-> 2 và 3-> 3. các phép nối này là cấp = 2. vì vậy chúng tôi có 9 tham gia ở đó, đó là lý do tại sao bạn nhận được 12 hàng (3 hàng gốc "cấp 1" hàng cộng với bộ Descartes).

nên số lượng đầu ra rows = rowcount + (rowcount^2)

trong truy vấn cuối cùng bạn đang cô lập mức này

select level as lvl 
      from dual 
     connect by level <= 2 

trong đó tất nhiên trả về 2 hàng. điều này sau đó được cartesianed đến 3 hàng ban đầu, cho 6 hàng như đầu ra.

11

Khi sử dụng connect by mà không có điều khoản start with và nhà điều hành prior, không có giới hạn nào khi tham gia hàng trẻ em vào hàng chính. Và những gì Oracle làm trong tình huống này, nó trả về tất cả hoán vị phân cấp có thể bằng cách kết nối một hàng với mỗi hàng cấp cao hơn.

SQL> select b 
    2  , level as lvl 
    3  , sys_connect_by_path(b, '->') as ph 
    4  from a 
    5 connect by level <= 2 
    6 ; 

     B  LVL PH 
     ---------- ---------- 
     1   1 ->1 
     1   2 ->1->1 
     2   2 ->1->2 
     3   2 ->1->3 
     2   1 ->2 
     1   2 ->2->1 
     2   2 ->2->2 
     3   2 ->2->3 
     3   1 ->3 
     1   2 ->3->1 
     2   2 ->3->2 
     3   2 ->3->3 

12 rows selected 
+2

'sys_connect_by_path()' <- từ khóa này giải thích mọi thứ. Một trong những câu trả lời hay nhất về câu hỏi này (không chỉ trong chủ đề này). – RIKI

0

Bạn có thể sử dụng kỹ thuật dưới đây để khắc phục vấn đề này:

select id, level as lvl 
    from a 
     left outer join (select level l from dual connect by level <= 2) lev on 1 = 1 
order by id 
Các vấn đề liên quan