我如何重构具有多个联合的代码
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 结果。第一个客户可以创建他们自己的视图版本,但是当他们想要使用它时,另一个客户可能已经替换了它。
因此,有各种更好的解决方案,例如
- 具有视图中所有 table 的 'big' 并集。从结果中过滤掉不需要的行。这看起来效率低下,但速度可能出奇地快,尤其是当您使用
UNION ALL
而不是 UNION
时。后者过滤掉重复的行,看起来你不需要那个。
- 创建
pipelined table function
。一个接一个地打开所需的查询,并将它们的结果通过管道输出到输出。您可以将该函数用作一种参数化视图。
- 创建一个生成所需查询的函数,而不是将其存储为视图,return 基于查询的游标 (
sys_refcursor
)。调用者可以读取该游标的结果。其他客户端可以连续调用,得到自己的游标,互不干扰
- 上述两者的混合将是编写一个生成查询的函数,批量收集 table 类型的结果并 returns 它。实现起来非常简单,但内存效率可能较低,因此对于较大的结果集,suitable 较少。
- 如果您使用的是最新的创新版本之一,则可以使用 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;
/
我有一个包,我需要根据参数多次执行相同(或相似)的并集或根本不需要。下面的代码被简化了。但真正的会有点复杂。因为我希望避免动态语句,所以我创建了一个临时视图并在此视图上执行操作。
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 结果。第一个客户可以创建他们自己的视图版本,但是当他们想要使用它时,另一个客户可能已经替换了它。
因此,有各种更好的解决方案,例如
- 具有视图中所有 table 的 'big' 并集。从结果中过滤掉不需要的行。这看起来效率低下,但速度可能出奇地快,尤其是当您使用
UNION ALL
而不是UNION
时。后者过滤掉重复的行,看起来你不需要那个。 - 创建
pipelined table function
。一个接一个地打开所需的查询,并将它们的结果通过管道输出到输出。您可以将该函数用作一种参数化视图。 - 创建一个生成所需查询的函数,而不是将其存储为视图,return 基于查询的游标 (
sys_refcursor
)。调用者可以读取该游标的结果。其他客户端可以连续调用,得到自己的游标,互不干扰 - 上述两者的混合将是编写一个生成查询的函数,批量收集 table 类型的结果并 returns 它。实现起来非常简单,但内存效率可能较低,因此对于较大的结果集,suitable 较少。
- 如果您使用的是最新的创新版本之一,则可以使用 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;
/