2017-07-20 4 views
2

J'ai deux types d'instruction select avec la même clause where complexe.requête de sélection multiple avec la même clause where

One - transaction Renvoie des données détaillées

select field_1, field_2, field_3, ... , field_30 from my_table where my_where_clause 

deuxième - données de transaction retours regroupés par les marchands (distincts)

select distinct field_1, field_2, field_8 from my_table where my_where_clause 

déclarations sont appelés séparément.

Je veux simplifier mon code et de ne pas répéter ce complexe où la clause dans les deux déclarations sans perdre les performances

Dans SQL dynamique, il est possible, mais je ne veux pas utiliser SQL dynamique.

Des suggestions?

+0

SQL dynamique peut être une option – SomeJavaGuy

+0

Oui c'est, mais je veux éviter SQL dynamique – mariami

+1

Le 2ème est dérivable de la première, donc en insérant le premier dans une table temporaire et interroger cela peut être une option. –

Répondre

1

Vous pouvez encapsuler cette déclaration, dans une ou fonction, e, g ,:

create or replace view view_1 as 
    select field_1, field_2, field_3, ... , field_30 
    from my_table 
    where my_where_clause 

Ensuite, votre deuxième requête pourrait être

select distinct * from view_1; 
+0

Je ne peux pas utiliser VIEW car j'ai beaucoup de paramètres dans ma clause where. Je ne peux pas utiliser la fonction parce que dans ce cas je dois retourner Cursor dans la fonction secondaire et Boucler dessus dans ma fonction principale. – mariami

+0

Merci pour le commentaire, j'ai ajouté quelques détails. – mariami

+0

Je veux simplifier mon code pour que je n'aie pas à écrire mon compliqué où cause dans les deux déclarations. Ces requêtes sont presque identiques. – mariami

0

Vous avez dit que vous utilisez cette requête de Java. Essaye ça.

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; 

Et l'utilisation de cela de 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(); 

Autre solution. Ajoutez un paramètre supplémentaire et effectuez une déduplication simple en utilisant toutes les colonnes de la requête. Mais je ne vois aucun avantage.

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; 
+0

Ceci est une solution utilisant le SQL dynamique. Je ne veux pas utiliser le SQL dynamique – mariami

+0

Ok, Sans SQL dynamique, une simple requête, mais les performances seront probablement pire. –

2

Suggestion: vous pouvez essayer GROUPING SETS expression. Il vous permet de spécifier de manière sélective l'ensemble de groupes que vous souhaitez créer dans une clause GROUP BY. Dans

Dans votre cas, vous pouvez spécifier 2 ensembles, un groupe par groupe pour tous les champs de 1 à 30 et un autre ensemble pour les champs 1,2 & 8. Link- https://docs.oracle.com/cd/E40518_01/server.761/es_eql/src/reql_aggregation_grouping_sets.html

Cependant, il retournera la sortie des deux groupes dans un seul ensemble de résultats, pas sûr si cela correspond à votre conception.

0

Vous pouvez rendre le SQL dynamique plus lisible en utilisant des chaînes multilignes, des citations alternatives et des modèles.

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

Ce n'est pas parfait mais il empêche la concaténation laide. Et c'est bien mieux que les anti-patterns nécessaires pour éviter le SQL dynamique à tout prix. Dans la plupart des langages, des fonctionnalités comme le polymorphisme et la réflexion sont préférables au code dynamique. PL/SQL ne supporte pas bien ces fonctionnalités avancées, il est donc préférable de générer le code sous forme de chaîne.