2010-06-23 10 views
5

Il peut être une question de débutant, mais toujours ..Tableau de correspondance des décodages oracle?

Nous sommes tous familiers avec les décodages et les cas d'Oracle, par exemple.

select 
    decode (state, 
      0, 'initial', 
      1, 'current', 
      2, 'finnal', 
      state) 
from states_table 

Ou le même genre de chose en utilisant CASE.

Maintenant, nous allons dire que j'ai une table avec ces mêmes valeurs:

state_num | state_desc 
     0 | 'initial' 
     1 | 'current' 
     2 | 'finnal' 

est-il un moyen que je pouvais faire la même requête en utilisant ce tableau comme une ressource pour le décodage? S'il vous plaît noter que je ne veux pas joindre la table pour accéder aux données de l'autre tableau ... je veux juste savoir s'il y a quelque chose que je pourrais utiliser pour faire une sorte de decode(myField, usingThisLookupTable, thisValueForDefault).

Répondre

3

Au lieu d'une jointure, vous pouvez utiliser une sous-requête, à savoir

select nvl(
    (select state_desc 
    from lookup 
    where state_num=state),to_char(state)) 
from states_table; 
+0

C'est vrai, c'est possible. Mais pas utile. Je vais reformuler ma réponse si :-) –

+0

Cela ferait juste ça. Je ne suis pas trop familier avec les compromis de cette pratique, mais si une petite question que je traite où un décodage massif rendrait très désordonné :(@ammoQ, auriez-vous une suggestion pour une valeur par défaut? Applaudissements! – filippo

+0

EDIT : un peu plus pour donner une valeur par défaut –

2

Non, il n'y a pas d'autre moyen, en plus d'utiliser une jointure à votre deuxième table. Bien sûr, vous pourriez écrire une sous-requête scalaire dans votre clause select, ou vous pourriez écrire votre propre fonction, mais ce serait une pratique inefficace.

Si vous avez besoin des données de la table, vous devez en choisir une.

EDIT: Je dois affiner ma déclaration précédente sur la pratique inefficace. Lorsque vous utilisez une sous-requête scalaire dans votre liste de sélection, vous vous attendez à ce que vous forçiez un plan semblable à une boucle imbriquée, où la sous-requête scalaire est exécutée pour chaque ligne de la table states_table. Au moins, je m'attendais à ça :-). Toutefois, Oracle a implémenté la mise en cache des sous-requêtes scalaires, ce qui conduit à une optimisation très intéressante. Il n'exécute que la sous-requête 3 fois. Il y a un excellent article sur les sous-requêtes scalaires où vous pouvez voir que plus de facteurs jouent un rôle dans la façon dont cette optimisation se comporte: http://www.oratechinfo.co.uk/scalar_subqueries.html#scalar3

Voici mon propre test pour voir cela au travail. Pour une simulation de vos tables, je ce script:

create table states_table (id,state,filler) 
as 
select level 
     , floor(dbms_random.value(0,3)) 
     , lpad('*',1000,'*') 
    from dual 
connect by level <= 100000 
/
alter table states_table add primary key (id) 
/
create table lookup_table (state_num,state_desc) 
as 
select 0, 'initial' from dual union all 
select 1, 'current' from dual union all 
select 2, 'final' from dual 
/
alter table lookup_table add primary key (state_num) 
/
alter table states_table add foreign key (state) references lookup_table(state_num) 
/
exec dbms_stats.gather_table_stats(user,'states_table',cascade=>true) 
exec dbms_stats.gather_table_stats(user,'lookup_table',cascade=>true) 

Ensuite, exécutez la requête et un regard sur le réel plan d'exécution:

SQL> select /*+ gather_plan_statistics */ 
    2   s.id 
    3  , s.state 
    4  , l.state_desc 
    5 from states_table s 
    6   join lookup_table l on s.state = l.state_num 
    7/

     ID  STATE STATE_D 
---------- ---------- ------- 
     1   2 final 
... 
    100000   0 initial 

100000 rows selected. 

SQL> select * from table(dbms_xplan.display_cursor(null,null,'allstats last')) 
    2/

PLAN_TABLE_OUTPUT 
-------------------------------------------------------------------------------------------------------------------------------------- 
SQL_ID f6p6ku8g8k95w, child number 0 
------------------------------------- 
select /*+ gather_plan_statistics */  s.id  , s.state  , l.state_desc from states_table s  join 
lookup_table l on s.state = l.state_num 

Plan hash value: 1348290364 

--------------------------------------------------------------------------------------------------------------------------------- 
| Id | Operation   | Name   | Starts | E-Rows | A-Rows | A-Time | Buffers | Reads | OMem | 1Mem | Used-Mem | 
--------------------------------------------------------------------------------------------------------------------------------- 
|* 1 | HASH JOIN   |    |  1 | 99614 | 100K|00:00:00.50 | 20015 | 7478 | 1179K| 1179K| 578K (0)| 
| 2 | TABLE ACCESS FULL| LOOKUP_TABLE |  1 |  3 |  3 |00:00:00.01 |  3 |  0 |  |  |   | 
| 3 | TABLE ACCESS FULL| STATES_TABLE |  1 | 99614 | 100K|00:00:00.30 | 20012 | 7478 |  |  |   | 
--------------------------------------------------------------------------------------------------------------------------------- 

Predicate Information (identified by operation id): 
--------------------------------------------------- 

    1 - access("S"."STATE"="L"."STATE_NUM") 


20 rows selected. 

maintenant la même chose pour la variante de sous-requête scalaire:

SQL> select /*+ gather_plan_statistics */ 
    2   s.id 
    3  , s.state 
    4  , (select l.state_desc 
    5    from lookup_table l 
    6   where l.state_num = s.state 
    7  ) 
    8 from states_table s 
    9/

     ID  STATE (SELECT 
---------- ---------- ------- 
     1   2 final 
... 
    100000   0 initial 

100000 rows selected. 

SQL> select * from table(dbms_xplan.display_cursor(null,null,'allstats last')) 
    2/

PLAN_TABLE_OUTPUT 
-------------------------------------------------------------------------------------------------------------------------------------- 
SQL_ID 22y3dxukrqysh, child number 0 
------------------------------------- 
select /*+ gather_plan_statistics */  s.id  , s.state  , (select l.state_desc 
from lookup_table l   where l.state_num = s.state  ) from states_table s 

Plan hash value: 2600781440 

--------------------------------------------------------------------------------------------------------------- 
| Id | Operation     | Name   | Starts | E-Rows | A-Rows | A-Time | Buffers | Reads | 
--------------------------------------------------------------------------------------------------------------- 
| 1 | TABLE ACCESS BY INDEX ROWID| LOOKUP_TABLE |  3 |  1 |  3 |00:00:00.01 |  5 |  0 | 
|* 2 | INDEX UNIQUE SCAN   | SYS_C0040786 |  3 |  1 |  3 |00:00:00.01 |  2 |  0 | 
| 3 | TABLE ACCESS FULL   | STATES_TABLE |  1 | 99614 | 100K|00:00:00.30 | 20012 | 9367 | 
--------------------------------------------------------------------------------------------------------------- 

Predicate Information (identified by operation id): 
--------------------------------------------------- 

    2 - access("L"."STATE_NUM"=:B1) 


20 rows selected. 

Et regardez la colonne Démarrage des étapes 1 et 2: seulement 3! Si cette optimisation est toujours une bonne chose dans votre situation, cela dépend de nombreux facteurs.

Vous pouvez vous référer à l'article mentionné précédemment pour voir l'effet de certains.

Dans votre situation avec seulement trois états, il semble que vous ne pouvez pas vous tromper avec la variante de sous-requête scalaire.

Cordialement, Rob.

+0

ouais .. compagnonC'est ce que je ne veux pas comme je l'ai souligné dans "S'il vous plaît noter que je ne veux pas joindre la table pour accéder aux données de l'autre table ..." La situation est que je suis coincé dans un système qui me permettra pour entrer les paramètres pour chaque champ que je veux, mais ne me laissera pas éditer le reste de la requête. C'est pourquoi je peux utiliser un décodage, mais je ne peux pas utiliser de jointure. – filippo

+0

J'ai édité ma réponse parce que j'ai arrêté de lire trop tôt. –

+0

-1 pour "pratique inefficace". En pratique, les frais généraux sont très faibles et valent bien le compromis de rendre le code compréhensible, ce qui est un énorme avantage. Il y a eu beaucoup de discussions sur le support enum dans les bases de données relationnelles - essayez google pour un mélange de discussions informées et imparfaites. – symcbean