园子里好象用 Oracle 数据库的人不是很多,写一个利用 PL/SQL 拆分字段的函数,供大家和 T-SQL 的语法做个对比吧。

原表:

拆分后的结果:

 

函数代码如下(在 PL/SQL Developer7.0.2 和 Oracle 10G 下测试通过):

create or replace function fun_SplitField(TableName in varchar2, FieldName in varchar2) return sys_refcursor is
  Result sys_refcursor;
  
  -- Author  : Clark Zheng
  -- Created : 2007-4-10 15:31:39
  -- Purpose : 拆分字段
    
  --临时表名称
  tmpTableName constant varchar2(50) := 'TMPTABLE';  
  
  a_cursor sys_refcursor;
  tmpNum number;
  tmpText varchar2(50);
  tmpIndex number;
  tmpStr varchar2(50);    
  sqlStr varchar2(500);
begin
  --如果参数不合法直接返回
  if TableName is null or FieldName is null then 
     dbms_output.put_line('参数为空');
     return(Result);
  end if;
     
  --如果没有临时表就创建临时表
  execute immediate 'select count(*) from user_tables where table_name=''' || tmpTableName || '''' into tmpNum;
  if tmpNum < 1 then
    execute immediate 'create GLOBAL TEMPORARY table ' || tmpTableName || ' (' || FieldName || ' varchar2(50)) ON COMMIT DELETE ROWS';
  end if;
 
  sqlStr := 'select distinct ' || FieldName || ' from ' || TableName;
  open a_cursor for sqlStr;
  
  loop
    fetch a_cursor into tmpText;
    --如果记录为空直接进入下一次循环
    if a_cursor%notfound then
       exit;
    end if;
    
    --判断字段的值是否为空
    if tmpText is not null then
      --获取逗号出现的位置
      select instr(tmpText, ',') into tmpIndex from dual;
      loop
        if tmpIndex <> 0 then
          --取得逗号前字符串
          select substr(tmpText, 1, tmpIndex - 1) into tmpStr from dual;
          --插入到临时表
          execute immediate 'insert into ' || tmpTableName || ' values (' || tmpStr || ')';
          --截取剩余的子符串
          select substr(tmpText, tmpIndex + 1) into tmpText from dual;
          --重新获取逗号出现的位置
          select instr(tmpText, ',') into tmpIndex from dual;
        else
          --保证最后一个子串被插入到临时表
          execute immediate 'insert into ' || tmpTableName || ' values (' || tmpStr || ')';
          exit;
        end if;
       end loop;
    end if;
  end loop;
  
  close a_cursor;
  
  --查询结果集
  sqlStr := 'select distinct * from ' || tmpTableName;
  open Result for sqlStr;
  
  return(Result);
 
  exception
    when others then
      --发生异常输出错误信息并返回空值,实际应用中可以抛出自定义异常
      dbms_output.put_line(dbms_utility.format_error_stack);
      return(Result);  
end fun_SplitField;

 

例子下载:https://files.cnblogs.com/reonlyrun/SplitFieldExample.rar

 

注:创建临时表要求用户必须具有“CREATE ANY TABLE”的权限

 

ps:本函数使用临时表加双层循环实现,效率不是很理想,希望有人提出更好的思路

Posted on 2007-04-11 17:43  Clark Zheng  阅读(2478)  评论(2编辑  收藏  举报