2010-06-23 37 views
5

Nó có thể là một câu hỏi mới, nhưng vẫn ..Bảng tra cứu để giải mã oracle?

Chúng ta đều quen thuộc với các giải mã và trường hợp của Oracle, ví dụ:

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

Hoặc cùng một loại điều sử dụng CASE.

Bây giờ chúng ta hãy nói rằng tôi có một bảng với các giá trị như nhau:

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

là có cách nào tôi có thể làm điều đó cùng một truy vấn sử dụng bảng này như một nguồn tài nguyên cho giải mã? Xin lưu ý rằng tôi không muốn nối bảng để truy cập dữ liệu từ bảng khác ... tôi chỉ muốn biết nếu có điều gì tôi có thể sử dụng để thực hiện một loại decode(myField, usingThisLookupTable, thisValueForDefault).

Trả lời

3

Thay vì một tham gia, bạn có thể sử dụng một subquery, ví dụ:

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

Đúng, có thể. Nhưng không thể. Tôi sẽ reword câu trả lời của tôi mặc dù :-) –

+0

Điều này sẽ chỉ làm điều đó. Tôi không quá quen thuộc với sự cân bằng của thực tế này, nhưng nếu một truy vấn nhỏ tôi đang đối phó với nơi mà một giải mã lớn sẽ làm cho nó rất lộn xộn: (@ammoQ, bạn sẽ có một gợi ý cho một giá trị mặc định? Chúc mừng! – filippo

+0

EDIT : nhiều hơn một chút để cung cấp một giá trị mặc định –

2

Không, không có cách nào khác ngoài việc sử dụng kết nối với bảng thứ hai của bạn. Chắc chắn, bạn có thể viết truy vấn con vô hướng trong mệnh đề lựa chọn của bạn, hoặc bạn có thể viết hàm riêng của bạn, nhưng đó sẽ là thực hành không hiệu quả.

Nếu bạn cần dữ liệu từ bảng, bạn cần chọn từ đó.

EDIT: Tôi phải tinh chỉnh tuyên bố trước đó của mình về thực tiễn không hiệu quả.

Khi sử dụng truy vấn phụ vô hướng trong danh sách lựa chọn của bạn, bạn mong đợi rằng bạn đang buộc một kế hoạch giống như vòng lặp lồng nhau, nơi truy vấn con vô hướng được thực thi cho mỗi hàng của states_table. Ít nhất tôi mong rằng :-).

Tuy nhiên, Oracle đã triển khai bộ nhớ đệm truy vấn phụ vô hướng, dẫn đến tối ưu hóa thực sự tốt đẹp. Nó chỉ thực hiện truy vấn con 3 lần. Có một bài viết tuyệt vời về truy vấn phụ vô hướng nơi bạn có thể thấy rằng nhiều yếu tố đóng vai trò trong cách tối ưu hóa này hoạt động: http://www.oratechinfo.co.uk/scalar_subqueries.html#scalar3

Đây là thử nghiệm riêng của tôi để xem công việc này. Đối với một mô phỏng của bảng của bạn, tôi đã sử dụng kịch bản này:

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) 

Sau đó, thực hiện truy vấn và có một cái nhìn tại các kế hoạch thực hiện thực:

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. 

Bây giờ làm tương tự cho các biến thể subquery vô hướng:

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. 

Và xem cột Bắt đầu ở bước 1 và 2: chỉ 3!

Cho dù tối ưu hóa này luôn là điều tốt trong tình huống của bạn, phụ thuộc vào nhiều yếu tố. Bạn có thể tham khảo bài viết đã đề cập trước đó để xem hiệu quả của một số bài viết.

Trong trường hợp của bạn chỉ với ba trạng thái, có vẻ như bạn không thể làm sai với biến thể truy vấn phụ vô hướng.

Trân trọng, Rob.

+0

vâng bạn đời ..đó là những gì tôi không muốn như tôi nhấn mạnh trong "Xin lưu ý rằng tôi không muốn nối bảng để truy cập dữ liệu từ bảng khác ..." Tình hình là tôi bị mắc kẹt trong một hệ thống mà sẽ cho phép tôi để nhập thông số cho từng trường tôi muốn, nhưng sẽ không cho phép tôi chỉnh sửa phần còn lại của truy vấn. Đó là lý do tại sao tôi có thể sử dụng một giải mã, nhưng không thể sử dụng một tham gia. – filippo

+0

Tôi đã chỉnh sửa câu trả lời của mình vì tôi đã ngừng đọc quá sớm. –

+0

-1 cho "thực hành kém hiệu quả". Trong thực tế, chi phí rất nhỏ và cũng đáng để đánh đổi việc làm cho mã dễ hiểu - đó là một lợi ích rất lớn. Đã có rất nhiều cuộc thảo luận về hỗ trợ enum trong cơ sở dữ liệu quan hệ - hãy thử google cho một hỗn hợp của các cuộc thảo luận được thông báo và thiếu sót. – symcbean