2010-06-23 3 views
5

Это может быть вопрос новичков, но все же ..Таблица поиска для деколов декорации?

Мы все знакомы с декодами и случаями Oracle, например.

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

Или такая же вещь, используя CASE.

Теперь, скажем, у меня есть таблица с этими же значениями:

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

есть способ, которым я мог бы сделать то же запрос, используя эту таблицу в качестве ресурса для декодирования? Обратите внимание, что я не хочу сужать таблицу для доступа к данным из другой таблицы ... Я просто хочу знать, есть ли что-то, что я мог бы использовать, чтобы сделать вид decode(myField, usingThisLookupTable, thisValueForDefault).

ответ

3

Вместо того, чтобы присоединиться, вы могли бы использовать подзапрос, т.е.

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

Правда, это возможно. Но не советую. Я верну свой ответ, хотя :-) –

+0

Это просто сделало бы это. Я не слишком разбираюсь в компромиссах этой практики, но если небольшой вопрос, с которым я столкнулся, где массивный декодирование сделает его очень грязным :(@ammoQ, у вас есть предложение по умолчанию? Cheers! – filippo

+0

EDIT : немного больше, чтобы предоставить значение по умолчанию –

2

Нет, нет другого способа, кроме использования соединения со второй таблицей. Конечно, вы могли бы написать скалярный подзапрос в своем предложении select, или вы могли бы написать свою собственную функцию, но это было бы неэффективной практикой.

Если вам нужны данные из таблицы, вам необходимо выбрать их.

EDIT: У меня есть уточнение моего предыдущего заявления о неэффективной практике.

При использовании скалярного подзапроса в выбранном списке вы ожидаете, что вы создадите план в виде вложенного цикла, в котором скалярный подзапрос будет выполняться для каждой строки состояния_стандарта. По крайней мере, я ожидал, что :-).

Однако Oracle реализовала скалярное кэширование подзапросов, что приводит к действительно хорошей оптимизации. Он только выполняет подзапрос 3 раза. Существует отличная статья о скалярных подзапросах, где вы можете увидеть, что больше факторов играет роль в том, как ведет себя эта оптимизация: http://www.oratechinfo.co.uk/scalar_subqueries.html#scalar3

Вот мой собственный тест, чтобы увидеть это на работе. Для моделирования таблиц, я использовал этот скрипт:

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) 

Затем выполнить запрос и посмотреть на реальный план выполнения:

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. 

Теперь сделать то же самое для скалярного варианта подзапроса:

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. 

И посмотрите столбец Starts шага 1 и 2: только 3!

Является ли эта оптимизация всегда хорошей вещью в вашей ситуации, зависит от многих факторов. Вы можете обратиться к предыдущей статье, чтобы увидеть эффект некоторых.

В вашей ситуации с тремя состояниями, похоже, вы не ошибетесь в варианте скалярного подзапроса.

С уважением, Роб.

+0

да мат ..это то, чего я не хочу, как я подчеркнул в «Пожалуйста, обратите внимание, что я не хочу объединять таблицу для доступа к данным из другой таблицы ...» Ситуация в том, что я застрял в системе, которая позволит мне для ввода параметров для каждого поля, которое я хочу, но не позволяю мне редактировать остальную часть запроса. Вот почему я могу использовать декодирование, но не могу использовать соединение. – filippo

+0

Я отредактировал свой ответ, потому что я перестал читать слишком рано. –

+0

-1 для «неэффективной практики». На практике накладные расходы очень малы и стоит того, чтобы сделать код понятным - что является огромной выгодой. В реляционных базах данных было много дискуссий о поддержке enum - попробуйте Google для получения информации об информированных и ошибочных дискуссиях. – symcbean