2012-02-02 34 views
11

Nếu tôi có hai câu hỏi, mà tôi sẽ gọi horrible_query_1ugly_query_2, và tôi muốn thực hiện những điều sau hai trừ hoạt động trên chúng:Làm cách nào để sử dụng lại một truy vấn lớn mà không lặp lại nó?

(horrible_query_1) minus (ugly_query_2) 
(ugly_query_2) minus (horrible_query_1) 

Hoặc có lẽ tôi có một terribly_large_and_useful_query, và kết quả thiết lập nó tạo ra tôi muốn sử dụng như một phần của một số truy vấn trong tương lai.

Làm cách nào để tránh sao chép và dán cùng một truy vấn ở nhiều nơi? Làm thế nào tôi có thể "không lặp lại bản thân mình", và làm theo nguyên tắc DRY. Điều này có thể trong SQL?

Tôi đang sử dụng Oracle SQL. Các giải pháp SQL di động thích hợp hơn, nhưng nếu tôi phải sử dụng một tính năng cụ thể của Oracle (bao gồm cả PL/SQL) thì OK.

Trả lời

15

Sau đó

(horrible_query_1_VIEW) minus (ugly_query_2_VIEW) 

(ugly_query_2_VIEW) minus (horrible_query_1_VIEW) 

Hoặc, có lẽ, với một with clause:

with horrible_query_1 as (
    select .. .. .. 
    from .. .. .. 
) , 
ugly_query_2 as (
    select .. .. .. 
    .. .. .. 
) 
(select * from horrible_query_1 minus select * from ugly_query_2 ) union all 
(select * from ugly_query_2  minus select * from horrible_query_1) 
+0

tốt, nhưng tôi muốn để xử lý các mặt hàng độc đáo để horrible_query_1 khác biệt so với tôi xử lý các mục duy nhất cho ugly_query_2. Có thể cho biết đặt mục nào là duy nhất đối với truy vấn này không? EDIT: Các khung nhìn có thể là giải pháp tốt nhất cho SQL thuần túy. – Buttons840

+2

Chắc chắn, bao gồm hai hoạt động đã đặt của bạn trong các truy vấn bên ngoài với các lựa chọn bao gồm các cột cố định được gọi là Nguồn, tức là 'SELECT 'horrible_query_1' AS Source, *' và 'SELECT 'ugly_query_2' AS Source, *'. Bằng cách đó, UNION của bạn sẽ cung cấp cho bạn tất cả các cột từ truy vấn của bạn cộng với mã định danh nguồn. – JamieSee

+1

Ví dụ cuối cùng, sử dụng "with mệnh đề" đã rất hữu ích trong những năm qua kể từ khi tôi đã hỏi câu hỏi này. Những "với mệnh đề" đôi khi được gọi là biểu thức bảng chung (hoặc CTE). Đây là một số thuật ngữ hữu ích cần biết khi tìm kiếm thêm chi tiết. Các mệnh đề được thêm vào tiêu chuẩn SQL vào năm 1999 vì vậy hầu hết các cơ sở dữ liệu cần hỗ trợ chúng, ngoại trừ MySQL mà vẫn chưa thực hiện phần này của tiêu chuẩn hai mươi tuổi. – Buttons840

0

Nếu bạn vận hành với các giá trị, bạn có thể viết các chức năng. Ở đây bạn tìm thấy thông tin về cách thực hiện. Về cơ bản nó hoạt động như viết một hàm bằng bất kỳ ngôn ngữ nào. Bạn có thể xác định tham số và trả về giá trị. Điều này mang đến cho bạn khả năng tuyệt vời để viết mã chỉ một lần. Đây là cách bạn làm điều đó:

http://docs.oracle.com/cd/B19306_01/server.102/b14200/statements_5009.htm

4

Nếu bạn muốn sử dụng lại các văn bản SQL của các truy vấn, sau đó xác định quan điểm là cách tốt nhất, như describer trước đó.

Nếu bạn muốn sử dụng lại kết quả của truy vấn, thì bạn nên xem xét bảng tạm thời toàn cầu. Các bảng tạm thời này lưu trữ dữ liệu trong suốt thời gian phiên hoặc giao dịch (tùy theo bạn chọn). Chúng thực sự hữu ích trong trường hợp bạn cần sử dụng lại dữ liệu đã tính toán nhiều lần, đặc biệt nếu các truy vấn của bạn thực sự "xấu" và "khủng khiếp" (có nghĩa là chạy dài). Xem Temporary tables để biết thêm thông tin.

Nếu bạn cần giữ dữ liệu lâu hơn một phiên, bạn có thể xem xét lượt xem vật chất.

1

Bạn đã thử sử dụng RESULT_CACHE gợi ý trong truy vấn của mình chưa? Ngoài ra, bạn có thể

ALTER SESSION SET RESULT_CACHE_MODE=FORCE 

và xem nó có giúp ích hay không.

+1

Điều đó có thể giúp với hiệu suất, nhưng tôi nghĩ rằng câu hỏi này là nhiều hơn về phong cách mã hóa. –

1

Vì bạn đang sử dụng Oracle, tôi sẽ tạo các hàm Pipelined TABLE. Hàm lấy tham số và trả về một đối tượng (mà bạn phải tạo) và sau đó bạn SELECT * hoặc thậm chí các cột cụ thể từ nó bằng hàm TABLE() và có thể sử dụng nó với mệnh đề WHERE hoặc JOIN. Nếu bạn muốn một đơn vị tái sử dụng (một hàm) bạn không bị giới hạn chỉ trả về các giá trị (tức là một hàm vô hướng), bạn có thể viết một hàm trả về các hàng hoặc các tập bản ghi. một cái gì đó như thế này:

FUNCTION RETURN_MY_ROWS(Param1 IN type...ParamX IN Type) 
      RETURN PARENT_OBJECT PIPELINED 
      IS 
      local_curs cursor_alias; --you need a cursor alias if this function is in a Package 
      out_rec ROW_RECORD_OF_CUSTOM_OBJECT:=ROW_RECORD_OF_CUSTOM_OBJECT(NULL, NULL,NULL) --one NULL for each field in the record sub-object 
     BEGIN 
     OPEN local_curs FOR 
      --the SELECT query that you're trying to encapsulate goes here 
      -- and it can be very detailed/complex and even have WITH() etc.. 
     SELECT * FROM baseTable WHERE col1 = x; 

    -- now that you have captured the SELECT into a Cursor 
    -- here you put a LOOP to take what's in the cursor and put it in the 
    -- child object (that holds the individual records) 
      LOOP 
     FETCH local_curs --opening the ref-cursor 
      INTO out_rec.COL1, 
       out_rec.COL2, 
       out_rec.COL3; 
     EXIT WHEN local_curs%NOTFOUND; 
     PIPE ROW(out_rec); --piping out the Object 
     END LOOP; 
     CLOSE local_curs; -- always do this 
     RETURN; -- we're now done 
    END RETURN_MY_ROWS; 

sau khi bạn đã làm điều đó, bạn có thể sử dụng nó như vậy

SELECT * FROM TABLE(RETURN_MY_ROWS(val1, val2)); 

bạn có thể INSERT SELECT hoặc thậm chí CREATE TABLE ra khỏi nó, bạn có thể có nó trong tham gia .

thêm hai điều cần đề cập đến:

--ROW_RECORD_OF_CUSTOM_OBJECT is something along these lines 
CREATE or REPLACE TYPE ROW_RECORD_OF_CUSTOM_OBJECT AS OBJECT 
(
    col1 type; 
    col2 type; 
     ... 
    colx type; 
); 

và PARENT_OBJECT là một bảng của các đối tượng khác (với các định nghĩa lĩnh vực), chúng tôi chỉ cần thực hiện

create or replace TYPE PARENT_OBJECT IS TABLE OF ROW_RECORD_OF_CUSTOM_OBJECT; 

nên chức năng này cần hai đối tượng để hỗ trợ nó, nhưng một là một bản ghi, cái kia là một bảng của bản ghi đó (bạn phải tạo bản ghi đầu tiên).

Tóm lại, chức năng này dễ viết, bạn cần một đối tượng con (với các trường) và đối tượng cha sẽ đặt đối tượng con đó là kiểu TABLE của đối tượng con và bạn mở bản gốc bảng cơ sở tìm nạp SQL vào một SYS_REFCURSOR (mà bạn có thể cần phải bí danh) nếu bạn đang ở trong một gói và bạn đọc từ con trỏ đó từ một vòng lặp vào các bản ghi riêng lẻ. Hàm trả về một loại PARENT_OBJECT nhưng bên trong nó gói đối tượng phụ bản ghi với các giá trị từ con trỏ.

Tôi hy vọng công trình này cho bạn (có thể có vấn đề permissioning với DBA của bạn nếu bạn muốn tạo các đối tượng và chức năng Table) */

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