2012-02-02 74 views
11

如果我有兩個疑問,我會打電話給horrible_query_1ugly_query_2,我想對他們執行以下兩個減號操作:如何在不重複的情況下重用大型查詢?

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

或者,也許我有一個terribly_large_and_useful_query,結果把它產生我想要用作幾個未來查詢的一部分。

如何避免在多個位置複製和粘貼相同的查詢?我如何「不重複自己」,遵循DRY原則。這在SQL中可能嗎?

我正在使用Oracle SQL。可移植的SQL解決方案是可取的,但如果我必須使用Oracle的特定功能(包括PL/SQL),那就沒問題。

回答

15

然後

(horrible_query_1_VIEW) minus (ugly_query_2_VIEW) 

(ugly_query_2_VIEW) minus (horrible_query_1_VIEW) 

或者,也許,有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

好,但我想辦理獨特horrible_query_1項目不同於我辦理ugly_query_2唯一的項目。是否有可能通過此查詢分辨哪些項目是唯一的?編輯:視圖可能是普通SQL的最佳解決方案。 – Buttons840 2012-02-02 20:35:00

+2

當然,包住兩套操作外查詢與選擇,其中包括固定列稱爲來源,即'選擇「horrible_query_1」 AS源,*'和'選擇「ugly_query_2」 AS源,*'。這樣,您的UNION會爲您提供查詢中的所有列和源標識符。 – JamieSee 2012-02-02 20:45:43

+1

最後一個例子,使用「與條款」已經多年來非常有幫助的,因爲我原來問過這個問題。這些「帶子句」有時稱爲通用表表達式(或CTE)。在搜索更多細節時,這些是一些有用的術語。在1999年,with-clause被添加到SQL標準中,所以大多數數據庫都應該支持它們,除了MySQL仍然沒有實現二十年前的標準。 – Buttons840 2016-04-07 17:13:58

4

如果你想重用的查詢SQL文本,然後定義視圖是最好的方式,因爲描述者更早。

如果您想重複使用結果的查詢,那麼您應該考慮全球臨時表。這些臨時表存儲會話或交易期間的數據(無論您選擇哪個)。如果您需要多次重複使用計算的數據,這些特別有用,特別是如果您的查詢確實是「醜陋」和「可怕」(意思是長時間運行)。有關更多信息,請參閱Temporary tables

如果您需要保持數據的時間超過一個會話,您可以考慮物化視圖

1

您是否嘗試過在您的查詢中使用RESULT_CACHE提示?此外,你可以

ALTER SESSION SET RESULT_CACHE_MODE=FORCE 

看看是否有幫助。

+1

這可能有助於提高性能,但我認爲這個問題更多的是關於編碼風格。 – 2012-10-19 04:13:36

1

由於您使用的是Oracle,因此我會創建Pipelined TABLE函數。 該函數使用參數並返回一個對象(您必須創建它) ,然後使用TABLE()函數從中選擇*或甚至是特定的列,並可以將它用於WHERE子句或JOIN。如果你想要一個重用單元(一個函數),你不僅僅限於返回值(即一個標量函數),你可以編寫一個返回行或記錄集的函數。 是這樣的:

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; 

你做到了這一點後,你可以用它像這樣

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

可以插入SELECT甚至CREATE TABLE出來的,你可以把它在加入。

兩件事提:

--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; 
); 

和PARENT_OBJECT是其他對象的表(與字段定義),我們只是做

create or replace TYPE PARENT_OBJECT IS TABLE OF ROW_RECORD_OF_CUSTOM_OBJECT; 

所以這個功能需要兩個對象以支持它,但一個是一個記錄,另一個是該記錄的表格(你必須先創建記錄)。

簡而言之,該函數易於編寫,您需要一個子對象(包含字段)和一個父對象,該父對象將包含該子對象的類型爲TABLE的子對象,然後打開原始對象基表中讀取SQL成SYS_REFCURSOR(這可能需要alias)如果你在一個包,你從光標從一個循環到單個記錄讀取。 該函數返回一個類型PARENT_OBJECT的但在其內部與來自光標值包中的記錄的子對象。

我希望這對你的作品(有可能是你的DBA的權限管理問題,如果你想創建對象和表函數)*/

相關問題