诡异的DECODE函数

4220阅读 0评论2013-02-05 tomsyan
分类:Oracle

今天同事遇到下面一个问题:

order by decode(column_id,1,null,2,null,3,null,column_id);
有个问题,就是当列数大于10列时,column_id 的顺序成10,11,12,13,4,5,6,7,8,9了


这个排序的主要目的是让前3列排在后面,这3列的顺序无所谓。


对于小于10列的表是没问题的:


SQL> create table t(c1 number,c2 number,c3 number,c4 number,c5 number);

表已创建。

SQL> col column_name format a20
SQL> select column_name,column_id
  2  from  user_tab_columns
  3  where table_name='T'
  4  order by decode(column_id,1,null,2,null,3,null,column_id);


COLUMN_NAME           COLUMN_ID
-------------------- ----------
C4                            4
C5                            5
C2                            2
C1                            1
C3                            3

但是当表的列数大于10的时候就会混乱了。


SQL> select column_name,column_id, decode(column_id,1,null,2,null,3,null,column_id) sortcolumn
  2  from  user_tab_columns
  3  where table_name='T'
  4  order by decode(column_id,1,null,2,null,3,null,column_id)
  5  /


COLUMN_NAME           COLUMN_ID SORTCOLUMN
-------------------- ---------- --------------------
C10                          10 10
C11                          11 11
C12                          12 12
C4                            4 4
C5                            5 5
C6                            6 6
C7                            7 7
C8                            8 8
C9                            9 9
C3                            3
C2                            2
C1                            1


已选择12行。


显然ORACLE把SORTCOLUMN列作为为字符类型排序了。

加个TO_NUMBER即可解决这个问题。


SQL> select column_name,column_id, decode(column_id,1,null,2,null,3,null,column_id) sortcolumn
  2  from  user_tab_columns
  3  where table_name='T'

  4  order by to_number(decode(column_id,1,null,2,null,3,null,column_id));


COLUMN_NAME           COLUMN_ID SORTCOLUMN
-------------------- ---------- --------------------
C4                            4 4
C5                            5 5
C6                            6 6
C7                            7 7
C8                            8 8
C9                            9 9
C10                          10 10
C11                          11 11
C12                          12 12
C1                            1
C3                            3
C2                            2


已选择12行。

但是为什么会导致这个问题,DECODE函数为何返回了字符类型。


这个问题yangtingkun大师专门写个几篇文章介绍。
有兴趣的可以找找看看。


在这里我借花献佛简单稍微说一下:
对于NULL 类型,ORACLE的默认返回类型是VARCHAR。
对于DECODE函数 ORACLE返回的类型依赖于第一个值。

如下所示:


SQL> CREATE TABLE A AS SELECT DECODE(DUMMY,'X',1,'Y','2',DUMMY) C1, <---由于第一个返回的值1是整数类型,因此整个表达式返回整数类型
  2  DECODE(DUMMY,'X','1','Y',2,DUMMY) C2 , <---由于第一个返回的值'1'是字符类型,因此整个表达式返回CHAR类型
  3  DECODE(DUMMY,'X',NULL,'Y','HUATENG',DUMMY) C3 FROM DUAL; <---由于第一个返回的值是NULL,因此整个表达式返回CHAR类型

表已创建。

SQL> DESC A
 名称                                      是否为空? 类型
 ----------------------------------------- -------- ----------------------------
 C1                                                 NUMBER
 C2                                                 VARCHAR2(1)
 C3                                                 VARCHAR2(7)
 
也正是因为DECODE函数的这种依赖于第一次的值类型作为返回类型,对于其他返回的值如果和第一个类型不匹配
,可能会让你遇到很蛋疼的问题:

SQL> DESC A;
 名称                                      是否为空? 类型
 ----------------------------------------- -------- ----------------------------
 C1                                                 NUMBER
 C2                                                 VARCHAR2(1)
 C3                                                 VARCHAR2(7)
 
SQL> INSERT INTO A VALUES(2,2,2);

已创建 1 行。

SQL> SELECT * FROM A;

        C1 C2 C3
---------- -- --------------
         1 1
         2 2  2


SQL> SELECT DECODE(C1,1,1,2,'E',C1) FROM A;
ERROR:
ORA-01722: 无效数字

未选定行

SQL> SELECT DECODE(C1,1,1,2,'E',C1) FROM A WHERE C1=1;

DECODE(C1,1,1,2,'E',C1)
-----------------------
                      1

SQL> SELECT DECODE(C1,1,1,2,'E',C1) FROM A WHERE C1=2;
SELECT DECODE(C1,1,1,2,'E',C1) FROM A WHERE C1=2
                       *
第 1 行出现错误:
ORA-01722: 无效数字


上面的问题主要是字符'E'无法转为整数类型导致的。
上一篇:DB2的CRASH RECOVERY
下一篇:Pro*C调用存储过程返回的游标