Oracle 具有相同where子句的多个select查询
我有两种类型的select语句,它们具有相同的复杂where子句 一次返回事务详细数据 第二个-返回按不同商户分组的交易数据 语句是单独调用的 我希望简化我的代码,不要在两条语句中重复这个复杂的where子句,而不会降低性能 在动态SQL中这是可能的,但我不想使用动态SQLOracle 具有相同where子句的多个select查询,oracle,plsql,where-clause,code-design,Oracle,Plsql,Where Clause,Code Design,我有两种类型的select语句,它们具有相同的复杂where子句 一次返回事务详细数据 第二个-返回按不同商户分组的交易数据 语句是单独调用的 我希望简化我的代码,不要在两条语句中重复这个复杂的where子句,而不会降低性能 在动态SQL中这是可能的,但我不想使用动态SQL 有什么建议吗 因此您可以将此语句封装在视图或函数中,例如: create or replace view view_1 as select field_1, field_2, field_3, ... , field_
有什么建议吗 因此您可以将此语句封装在视图或函数中,例如:
create or replace view view_1 as
select field_1, field_2, field_3, ... , field_30
from my_table
where my_where_clause
那么您的第二个查询可能是
select distinct * from view_1;
您说过您正在使用来自java的这个查询。试试这个
create or replace function get_cursor(p_type varchar2 default null/* other paramethers*/ ) return sys_refcursor
is
result_curosr sys_refcursor;
begin
open result_curosr for 'select '||p_type||' object_type,status from user_objects' /* where clausele */ ;
return result_curosr;
end;
以及它在java中的用法
Connection con = ...
CallableStatement callableStatement = con.prepareCall("declare c sys_refcursor; begin ? := get_cursor(?); end ; ");
callableStatement.registerOutParameter(1, OracleTypes.CURSOR);
callableStatement.setString(2, "Distinct"); // for distinct
or
callableStatement.setNull(2, OracleTypes.VARCHAR); // for full results
callableStatement.executeUpdate();
ResultSet rs = (ResultSet) callableStatement.getObject(1);
while(rs.next()) {
System.err.println(rs.getString(1));
}
rs.close();
con.close();
其他解决方案。
再添加一个参数,并使用查询中的所有列执行简单的重复数据消除。但我看不出有什么好处
select object_type,status from
(select object_type,status, row_number() over( partition by object_type,status order by 1) rn from user_objects /* your_where_clusue */
) where rn = case when 'DISTIINCT'/* <- paramete here :isDistinct */ = 'DISTIINCT' then 1 else rn end;
建议:您可以尝试对表达式集进行分组。
它允许您有选择地指定要在GROUPBY子句中创建的组集。在
在您的情况下,可以指定2个集合,一组一组用于1到30的所有字段,另一组用于1、2和8的字段。
链接-
但是,它将在单个结果集中返回两个组的输出,不确定这是否适合您的设计。您可以使用多行字符串、替代引号和模板使动态SQL更具可读性
declare
v_select varchar2(32767);
v_where varchar2(32767);
v_code varchar2(32767) := '
##SELECT##
##WHERE##
';
begin
--Populate the clauses.
if ... then
v_select := 'select field_1, field_2, field_3, ... , field_30 from my_table';
else
v_select := 'select distinct field_1, field_2, field_8 from my_table';
end if;
if ... then
v_where :=
q'[
where field_1 = 'foo'
and field_2 = :bind1
...
]';
else
v_where :=
q'[
where field_2 = 'bar'
and field_2 = :bind2
...
]';
end if;
--Fill in the code.
v_code := replace(v_code, '##SELECT##', v_select);
v_code := replace(v_code, '##WHERE##', v_where);
--Print the code to check the formatting. Remove after testing.
dbms_output.put_line(v_code);
--Run it.
execute immediate v_code using ...;
end;
/
它不是完美的,但它可以防止丑陋的连接。而且它比不惜一切代价避免动态SQL所需的反模式要好得多。在大多数语言中,多态性和反射等特性比动态代码更好。PL/SQL对这些高级功能没有很好的支持,因此通常最好将代码构建为字符串。动态SQL可能是一个选项,但我想避免动态SQL第二个是可以从第一个派生出来的,因此,将第一个插入临时表并查询可能是一个选项。在这种情况下,它将优化我的代码,但也会影响性能。为什么要避免使用动态SQL?我不能使用VIEW,因为我的where子句中有许多参数。我不能使用函数,因为在这种情况下,我必须在子函数中返回游标,并在主函数中循环它。感谢您的评论,我添加了一些细节。我想简化代码,这样我就不必在这两个语句中编写复杂的where原因。这些问题几乎是一样的。我想我现在明白你的意思了。我使用游标从函数返回这些查询的结果。这个函数是从Java代码中调用的。这就是你要写的吗?是的。请解释-如有必要,请使用伪代码-这两个查询如何适合我,我必须在子函数中返回游标,并在主函数中循环它。这是使用动态SQL的解决方案。我不想使用动态SQLOk,没有动态sql,只是简单的查询,但性能可能会更差。
select object_type,status from
(select object_type,status, row_number() over( partition by object_type,status order by 1) rn from user_objects /* your_where_clusue */
) where rn = case when 'DISTIINCT'/* <- paramete here :isDistinct */ = 'DISTIINCT' then 1 else rn end;
declare
v_select varchar2(32767);
v_where varchar2(32767);
v_code varchar2(32767) := '
##SELECT##
##WHERE##
';
begin
--Populate the clauses.
if ... then
v_select := 'select field_1, field_2, field_3, ... , field_30 from my_table';
else
v_select := 'select distinct field_1, field_2, field_8 from my_table';
end if;
if ... then
v_where :=
q'[
where field_1 = 'foo'
and field_2 = :bind1
...
]';
else
v_where :=
q'[
where field_2 = 'bar'
and field_2 = :bind2
...
]';
end if;
--Fill in the code.
v_code := replace(v_code, '##SELECT##', v_select);
v_code := replace(v_code, '##WHERE##', v_where);
--Print the code to check the formatting. Remove after testing.
dbms_output.put_line(v_code);
--Run it.
execute immediate v_code using ...;
end;
/