我如何重构具有多个联合的代码

How can I refactor the code with many unions

我有一个包,我需要根据参数多次执行相同(或相似)的并集或根本不需要。下面的代码被简化了。但真正的会有点复杂。因为我希望避免动态语句,所以我创建了一个临时视图并在此视图上执行操作。

PROCEDURE CREATE_VIEW( id IN BINARY_INTEGER, id2 IN BINARY_INTEGER, id3 IN BINARY_INTEGER) IS
sqlCommand VARCHAR2(32000);

BEGIN
    sqlCommand :=
    'CREATE OR REPLACE VIEW TMP_HELPER_VIEW AS 
    SELECT ID, IMPORT1_ID, IMPORT2_ID, PROD_ID
    FROM 
    (
        SELECT ID,
               IMPORT1_ID,
               -1 AS IMPORT2_ID,
               PROD_ID                
          FROM TABLE1
          WHERE IMPORT1> '|| id1;

       
    IF id := 123 THEN    
        sqlCommand := sqlCommand||
        'UNION
        SELECT ID,
               -1 AS IMPORT1_ID,
               IMPORT2_ID,
               PROD_ID               
          FROM TABLE2
          WHERE IMPORT2> '|| id2;
    END IF;
    sqlCommand := sqlCommand||')' ;
    EXECUTE IMMEDIATE  sqlCommand;                
        

END CREATE_VIEW;

鉴于我可以做到:

SELECT ID, IMPORT1_ID, IMPORT2_ID FROM TMP_HELPER_VIEW; 

而不是

 sqlCommand := 
          'SELECT ID,
           IMPORT1_ID,
           -1 AS IMPORT2_ID,
           PROD_ID                
      FROM TABLE1
      WHERE IMPORT1> '|| id1;
       
    IF id := 123 THEN    
        sqlCommand := sqlCommand||
        'UNION
        SELECT ID,
               -1 AS IMPORT1_ID,
               IMPORT2_ID,
               PROD_ID               
          FROM TABLE2
          WHERE IMPORT2> '|| id2;
    END IF;

所以代码的可读性会更好,因为我有许多使用类似语句的函数。语句总是有点不同,所以我每次都需要写它们(我不能在函数中写一个然后从那里调用每一次)。 但是我想知道这个问题是否有更好的解决方案。也许有人可以给我任何线索。 非常感谢!

无论如何,您都有一个动态语句,但除此之外,您还把它存储在一个视图中。用例对我来说不是很清楚。如果这是为 customer/installation 设置视图的某种一次性配置,我认为这可能没问题。

但是,如果您使用它来动态生成不同的查询,我认为这是有风险的。两个客户端可能会争先恐后地生成自己的视图版本,从而导致不需要的、不可预测的 table 结果。第一个客户可以创建他们自己的视图版本,但是当他们想要使用它时,另一个客户可能已经替换了它。

因此,有各种更好的解决方案,例如

  1. 具有视图中所有 table 的 'big' 并集。从结果中过滤掉不需要的行。这看起来效率低下,但速度可能出奇地快,尤其是当您使用 UNION ALL 而不是 UNION 时。后者过滤掉重复的行,看起来你不需要那个。
  2. 创建 pipelined table function。一个接一个地打开所需的查询,并将它们的结果通过管道输出到输出。您可以将该函数用作一种参数化视图。
  3. 创建一个生成所需查询的函数,而不是将其存储为视图,return 基于查询的游标 (sys_refcursor)。调用者可以读取该游标的结果。其他客户端可以连续调用,得到自己的游标,互不干扰
  4. 上述两者的混合将是编写一个生成查询的函数,批量收集 table 类型的结果并 returns 它。实现起来非常简单,但内存效率可能较低,因此对于较大的结果集,suitable 较少。
  5. 如果您使用的是最新的创新版本之一,则可以使用 SQL Macros 生成您需要的 SQL 片段。

很难说出哪一个最适合您的具体情况,但我已经在我们的应用程序中成功地使用了每一个。

4 的例子

create type IMPORT_R as object (
  ID int,
  IMPORT1_ID int,
  IMPORT2_ID int,
  PROD_ID int
);
create type IMPORT_T as table of IMPORT_R;

CREATE FUNCTION GetImport(
  id IN BINARY_INTEGER, 
  id2 IN BINARY_INTEGER, 
  id3 IN BINARY_INTEGER) 
return IMPORT_T
IS
  sqlCommand VARCHAR2(32000);
  v_Result IMPORT_T;
begin
    sqlCommand :=
        'SELECT ID, IMPORT1_ID, IMPORT2_ID, PROD_ID
        FROM 
        (
            SELECT ID,
                   IMPORT1_ID,
                   -1 AS IMPORT2_ID,
                   PROD_ID                
              FROM TABLE1
              WHERE IMPORT1> '|| id1;

       
    IF id := 123 THEN    
        sqlCommand := sqlCommand||
        'UNION
        SELECT ID,
               -1 AS IMPORT1_ID,
               IMPORT2_ID,
               PROD_ID               
          FROM TABLE2
          WHERE IMPORT2> '|| id2;
    END IF;
    
    sqlCommand := sqlCommand||')' ;
    
    EXECUTE IMMEDIATE sqlCommand BULK COLLECT INTO v_Result;
    
    return v_Result;
end;
/