Запрос множественного выбора с тем же предложением where
У меня есть два типа оператора select с таким же сложным предложением where.
One - возвращает подробные данные транзакции
select field_1, field_2, field_3, ... , field_30 from my_table where my_where_clause
Второй - возвращает данные транзакции, сгруппированные по (отдельным) торговцам
select distinct field_1, field_2, field_8 from my_table where my_where_clause
Заявления называются отдельно.
Я хочу упростить мой код и не повторять это сложное предложение where в обоих операторах без потери производительности
В динамическом SQL это возможно, но я не хочу использовать динамический SQL.
Какие-либо предложения?
4 ответа
Предложение: вы можете попробовать выражение GROUPING SETS. Это позволяет вам выборочно указывать набор групп, которые вы хотите создать в предложении GROUP BY. В
В вашем случае вы можете указать 2 набора: одна группа за набор для всех полей от 1 до 30, а другая группа для полей 1,2 и 8. Ссылка - https://docs.oracle.com/cd/E40518_01/server.761/es_eql/src/reql_aggregation_grouping_sets.html
Тем не менее, он вернет выходные данные обеих групп в одном наборе результатов, не уверен, что это вписывается в ваш дизайн.
Таким образом, вы можете заключить это утверждение в представление или функцию, например,
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;
Вы можете сделать динамический 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 не имеет хорошей поддержки для этих расширенных функций, поэтому обычно лучше построить код в виде строки.