Sql oracle解码的查找表?
这可能是一个新手问题,但 我们都熟悉甲骨文的解码和案例,例如Sql oracle解码的查找表?,sql,oracle,decode,Sql,Oracle,Decode,这可能是一个新手问题,但 我们都熟悉甲骨文的解码和案例,例如 select decode (state, 0, 'initial', 1, 'current', 2, 'finnal', state) from states_table 或者使用CASE的类似东西 现在让我们假设我有一个具有相同值的表: state_num | state_desc 0 | 'initial' 1
select
decode (state,
0, 'initial',
1, 'current',
2, 'finnal',
state)
from states_table
或者使用CASE的类似东西
现在让我们假设我有一个具有相同值的表:
state_num | state_desc
0 | 'initial'
1 | 'current'
2 | 'finnal'
是否有一种方法可以使用此表作为解码的资源来执行相同的查询?
请注意,我不想连接该表以访问另一个表中的数据。。。我只是想知道是否有什么东西可以用来进行某种
解码(myField,使用IsLookuptable,thisValueForDefault)
不,除了使用第二个表的联接之外,没有其他方法。当然,可以在select子句中编写标量子查询,也可以编写自己的函数,但这样做效率低下
如果需要表中的数据,则需要从中进行选择
编辑:
我必须改进我先前关于这种低效做法的陈述
在选择列表中使用标量子查询时,您可能希望强制执行一个嵌套的类似循环的计划,其中标量子查询针对states_表的每一行执行。至少我预料到:-)
然而,Oracle已经实现了标量子查询缓存,这导致了一个非常好的优化。它只执行子查询3次。有一篇关于标量子查询的优秀文章,在这篇文章中,您可以看到更多的因素在这种优化行为中发挥作用:
这里是我自己的测试,看看这在工作。为了模拟您的表,我使用了以下脚本:
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 , ( 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.
请看步骤1和步骤2的“开始”列:仅3
在您的情况下,这种优化是否总是一件好事取决于许多因素。您可以参考前面提到的文章来了解一些方法的效果
在只有三种状态的情况下,标量子查询变量似乎不会出错
问候,,
Rob.您可以使用子查询代替联接,即
select nvl(
(select state_desc
from lookup
where state_num=state),to_char(state))
from states_table;
是的,伙计。。正如我在“请注意,我不想连接表以访问另一个表中的数据…”中所强调的那样,这正是我不想要的。情况是,我被困在一个系统中,该系统允许我为我想要的每个字段输入参数,但不允许我编辑查询的其余部分。这就是为什么我可以使用解码,但不能使用连接。-1表示“低效练习”。在实践中,开销非常小,值得与代码的可理解性进行权衡,这是一个巨大的好处。关于关系数据库中的enum支持,已经有很多讨论了——尝试一下谷歌,让它混合了知情和有缺陷的讨论。没错,这是可能的。但这是不可取的。不过,我会改写我的答案:-)这样就行了。我不太熟悉这种做法的利弊权衡,但如果我处理的一个小问题是大规模解码将使其变得非常混乱:(@ammoQ,你对默认值有什么建议吗?干杯!编辑:再多提供一点默认值Rob van Wijk:建议与否…不要太迂腐。如果它能工作并且足够快,那么它就足够好了。子查询不一定慢,这取决于oracle执行联接的方式。我在这里运行了一个小测试,使用一个较小的查找表和一个较大的其他表,这两种方法在这个设置中速度相同
select nvl(
(select state_desc
from lookup
where state_num=state),to_char(state))
from states_table;