2012-04-06 44 views
7

THEO Tôi vừa chạy ngang qua interesting article here này, cho thấy làm thế nào để mô phỏng wm_concat() hoặc group_concat() trong Oracle sử dụng một truy vấn và cửa sổ thứ bậc chức năng:Oracle CONNECT BY khoản sau mệnh đề GROUP

SELECT deptno, 
     LTRIM(MAX(SYS_CONNECT_BY_PATH(ename,',')) 
     KEEP (DENSE_RANK LAST ORDER BY curr),',') AS employees 
FROM (SELECT deptno, 
       ename, 
       ROW_NUMBER() OVER (PARTITION BY deptno ORDER BY ename) AS curr, 
       ROW_NUMBER() OVER (PARTITION BY deptno ORDER BY ename) -1 AS prev 
     FROM emp) 
GROUP BY deptno 
CONNECT BY prev = PRIOR curr AND deptno = PRIOR deptno 
START WITH curr = 1; 

Mặc dù, tôi tìm thấy điều này không phải là một giải pháp rất dễ đọc, nó khá thú vị, đặc biệt vì mệnh đề CONNECT BY .. STARTS WITH đến sau mệnh đề GROUP BY. Theo số the specification, điều này không thể thực hiện được. Tôi đã thử điều này bằng cách sử dụng một truy vấn đơn giản và nó hoạt động, mặc dù! Hai truy vấn sau trả về cùng một kết quả:

-- wrong according to the specification: 
select level from dual group by level connect by level <= 2; 
-- correct according to the specification: 
select level from dual connect by level <= 2 group by level; 

Đây có phải là tính năng không có giấy tờ không? Hay chỉ là sự thờ ơ cú pháp để thuận tiện? Hoặc làm hai câu lệnh tinh tế hành xử khác nhau?

Trả lời

2

Tôi nghĩ đây chỉ là sự khác biệt về cú pháp không đáng kể.

Cụ thể hơn, tôi nghĩ đây là lỗi tài liệu. Sơ đồ cú pháp cho 8i ngụ ý rằng thứ tự được hỗ trợ. Không có gì trong các 8i reference ngụ ý thứ tự làm cho bất kỳ sự khác biệt. Nhưng sơ đồ đó cũng loại ngụ ý rằng bạn có thể có nhiều group_by_clause hoặc hierarchical_query, đó là không đúng sự thật:

--You can't group twice: ORA-01787: only one clause allowed per query block 
select level from dual connect by level <= 2 group by level group by level; 

tôi đoán là khi Oracle cố định sơ đồ cú pháp cho 9i họ cũng quên thứ tự có thể khác nhau. Hoặc có thể họ cố ý bỏ nó ra, bởi vì nó có vẻ hợp lý hơn để làm phần phân cấp đầu tiên.

Có một số biến thể cú pháp nhỏ như thế này không có giấy tờ. Tôi không nghĩ rằng nó có nghĩa là họ không được hỗ trợ. Oracle có thể hối tiếc cho phép nhiều tùy chọn kỳ lạ và muốn mọi thứ ít nhất là trông đơn giản. Ví dụ: HAVING có thể đến trước GROUP BY, nhiều tính năng song song cũ vẫn hoạt động (nhưng bị bỏ qua), v.v. (Đây là lý do tại sao tôi luôn cười khi mọi người nói rằng họ sẽ nhanh chóng "phân tích cú pháp SQL" - chúc may mắn tìm ra điều này !)

Oracle 8i cú pháp: Oracle 8i SELECT syntax

Oracle 9i cú pháp: Oracle 9i SELECT syntax

+0

Cảm ơn bạn đã nghiên cứu. Điều đó có ý nghĩa, tất nhiên. Sau khi tất cả, trong ký hiệu BNF, nó có thể khá khó khăn để tài liệu sự thờ ơ trật tự cho hai mệnh đề, như có thể thấy trong tài liệu [CONNECT BY .. START WITH/START WITH .. CONNECT BY] (http: // docs. oracle.com/cd/B28359_01/server.111/b28286/statements_10002.htm#i2126079), nơi điều này trở nên khá khó đọc. –

2

Nhìn vào các kế hoạch thực hiện. Trong môi trường của tôi, chúng giống hệt nhau, với hoạt động CONNECT BY được đưa vào HASH GROUP BY. Vì vậy, nó xuất hiện rằng đặt GROUP BY đầu tiên chỉ là một cú pháp lẻ tạo ra kết quả tương tự như thứ tự tự nhiên hơn.

Về mặt kỹ thuật, đây có thể là lỗi trong trình phân tích cú pháp, vì khi bạn nói thông số chỉ ra rằng mệnh đề truy vấn phân cấp phải đến trước mệnh đề nhóm theo. Nhưng nó không xuất hiện để làm cho bất kỳ sự khác biệt trong cách truy vấn được thực hiện.

+1

đẹp gợi ý. Tôi cũng nghĩ rằng đây là một lỗi (hoặc "tính năng ẩn") của trình phân tích cú pháp. Tuy nhiên, đây là một truy vấn tầm thường, kế hoạch thực hiện (hoặc thậm chí kết quả) vẫn có thể khác nhau trong một phức tạp hơn ... –

Các vấn đề liên quan