How to reuse a large query without repeating it?

后端 未结 5 1860
别那么骄傲
别那么骄傲 2020-12-31 06:58

If I have two queries, which I will call horrible_query_1 and ugly_query_2, and I want to perform the following two minus operations on them:

5条回答
  •  滥情空心
    2020-12-31 07:43

    Since you're using Oracle, I'd create Pipelined TABLE functions. The function takes parameters and returns an object (which you have to create) and then you SELECT * or even specific columns from it using the TABLE() function and can use it with a WHERE clause or with JOINs. If you want a unit of reuse (a function) you're not restricted to just returning values (i.e a scalar function) you can write a function that returns rows or recordsets. something like this:

    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;
    

    after you've done that, you can use it like so

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

    you can INSERT SELECT or even CREATE TABLE out of it , you can have it in joins.

    two more things to mention:

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

    and PARENT_OBJECT is a table of the other object (with the field definitions) we just made

    create or replace TYPE PARENT_OBJECT IS TABLE OF ROW_RECORD_OF_CUSTOM_OBJECT;
    

    so this function needs two OBJECTs to support it, but one is a record, the other is a table of that record (you have to create the record first).

    In a nutshell, the function is easy to write, you need a child object (with fields), and a parent object that will house that child object that is of type TABLE of the child object, and you open the original base-table fetching SQL into a SYS_REFCURSOR (which you may need to alias) if you're in a package and you read from that cursor from a loop into the individual records. The function returns a type of PARENT_OBJECT but inside it packs the records sub-object with values from the cursor.

    I hope this works for you (there may be permissioning issues with your DBA if you want to create OBJECTs and Table functions)*/

提交回复
热议问题