`
wuhuizhong
  • 浏览: 684571 次
  • 性别: Icon_minigender_1
  • 来自: 中山
社区版块
存档分类
最新评论

Creating and Unpacking Delimited Strings in SQL

 
阅读更多

Recently a friend asked me for this. I see it a lot on OraFaq as a question in the forums so here are the basics of working with delimited strings. I will show the various common methods for creating them and for unpacking them. Its not like I invented this stuff so I will also post some links for additional reading.

Here are some link for more reading:

http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:15637744429336
http://www.oracle-base.com/articles/10g/StringAggregationTechniques.php

Creating Delimited Strings

There are five basic methods for creating a delimited string in Oracle:

 

1) (my favorite) use a hierarchical query, also known as the sys_connect_by_path method
2) create a simple plsql function for your own needs
3) use an oracle supplied function DBMS_UTIL.TABLE_TO_COMMA and WM_CONCAT
4) bulid your own user defined aggregate (I first saw this on asktomhome)
5) even use XML (super ugly and not sure why anyone would do it this way so I won't show it)


sys_connect_by_path

 

In this method we take advantage of oracle's hierarchical processing in sql to do string concatenation all inside the sql statement.

 

SQL> select substr(sys_connect_by_path(table_name,','),2) table_list
  2  from (
  3         select rownum rowno,table_name
  4         from user_tables
  5         where rownum < 4
  6       )
  7  where connect_by_isleaf = 1
  8  connect by prior rowno = rowno - 1
  9  start with rowno = 1
 10  /

TABLE_LIST
------------------------------------------------------------------------------------
MV_UW_PROD_ASSIGNMENTS,MV_CALL_MEMO_REPORT,MV_SALES_TEAMS

1 row selected.

 

I like this because of its flexibility. You can supply any query you want without using any procedural code.

Simple PLSQL Function

Maybe the most common method is creating your own special purpose function. Not my favorite method as it usually is not general use and is not terribly efficient. There are many variations on this theme depending upon what the format of your incomming data is and how you get it ready for sending to the function. I have seen varations that use PLSQL table types and database object types and of course query parameters like this one.

 

create or replace function kev_get_string_list (query_p in varchar2) return varchar2 is
   c1 sys_refcursor;
   comma_seperated_list_v varchar2(4000);
   string_v varchar2(4000);
begin
   open c1 for query_p;
   loop
      fetch c1 into string_v;
      if c1%notfound then exit; end if;
      comma_seperated_list_v := comma_seperated_list_v||','||string_v;
   end loop;
   close c1;
   comma_seperated_list_v := substr(comma_seperated_list_v,2);
   return (comma_seperated_list_v);
end;
/
show errors

SQL> select kev_get_string_list('select table_name from user_tables where rownum < 4') thestring from dual;

THESTRING
---------------------------------------------------------------------------------------------------------------
MV_UW_PROD_ASSIGNMENTS,MV_CALL_MEMO_REPORT,MV_SALES_TEAMS

1 row selected.

 

Use an Oracle Supplied Function

DBMS_UTIL.TABLE_TO_COMMA does it but his is a procedure not a function and is not callable directly from sql. It also requires a plsql table input so has limited use outside of plsql. I won't bother with an example as it is in fact like the example above just shown.

But this is interesting. WM_CONCAT is an oracle supplied aggregate function that creates comma delimited strings.

 

SQL> select wm_concat(table_Name) comma_delimited_list
  2  from user_tables
  3  where rownum < 4
  4  /

COMMA_DELIMITED_LIST
-----------------------------------------------------------
CONTACT_POINT,ELECTRONIC_ADDRESS,POSTAL_ADDRESS

1 row selected.

 

But there are some issues:

1) it may or may not be documented depending upon your release.
2) you must have installed oracle workspace manager for it to be available.

Roll Your Own User Defined Aggregate

I first saw this on asktomhome. It may be the most natural method philosophically and most versatile. It is also the basic example of using user defined aggregate for something useful. We basically build our own WM_CONCAT so to speak.

 

create or replace type our_string_agg as object
(
   string_v varchar2(32767)
     ,static function odciaggregateinitialize(sctx in out our_string_agg) return number
     ,member function odciaggregateiterate(self in out our_string_agg, value in varchar2 ) return number
     ,member function odciaggregateterminate(self in our_string_agg, returnvalue out varchar2, flags in number) return number
     ,member function odciaggregatemerge(self in out our_string_agg, ctx2 in our_string_agg) return number
);
/
show errors


create or replace type body our_string_agg is
   static function odciaggregateinitialize(sctx in out our_string_agg)  return number is
   begin
      sctx := our_string_agg(null);
      return odciconst.success;
   end;

   member function odciaggregateiterate(self in out our_string_agg, value in varchar2)  return number is
   begin
      self.string_v := self.string_v || ',' || value;
      return odciconst.success;
   end;

   member function odciaggregateterminate(self in our_string_agg, returnvalue out varchar2, flags in number) return number is
   begin
      returnvalue := rtrim(ltrim(self.string_v, ','), ',');
      return odciconst.success;
   end;

   member function odciaggregatemerge(self in out our_string_agg, ctx2 in our_string_agg)  return number is
   begin
      self.string_v := self.string_v || ',' || ctx2.string_v;
      return odciconst.success;
   end;
end;
/
show errors


create or replace function agg_get_comma_delimited_string (data_in_p in varchar2) return varchar2
   parallel_enable
   aggregate
   using our_string_agg;
/
show errors

SQL> select agg_get_comma_delimited_string(table_name) comma_delimited_string
  2  from user_tables
  3  where rownum < 4
  4  /

COMMA_DELIMITED_STRING
--------------------------------------------------------------------------------------
CONTACT_POINT,ELECTRONIC_ADDRESS,POSTAL_ADDRESS

1 row selected.

 

It is my understanding that WC_CONCAT is in fact a "user defined aggregate" just defined by oracle for us. For those not familiar with user defined aggregates consider this:

SUM is an aggregate function. It operates across a set of rows. Could you write your own SUM function? Sure, you use the ODCIAggregate API to do it. Thus you can extend oracle with your own aggregate functions. Of course you need a reason to do it. This is one reason. Not many people have a reason so not many people use this. User Defined Aggregates were I believe created most to support Oracle's geocoding stuff.

As you can see UDA is somewhat involved. However, good things come from the effort. The result is another function that operates like all other functions. A very handy way to extend oracle if you have a need for it.

XML method

OK this method is ugly. It requires use of XMLAGG and XML_ELEMENT functions and multiple passes of the data and even when done is very unclear what it is doing. I won't show it, but you can easily find it with a google search.

Then there is the unpacking side of things. How does one unpack a delimited string. Well for this there are two basic methods:

1) sql method
2) function method

Unpacking is less exciting than packing.

The SQL Method

This is pretty much the reverse of the sys_connect_by_path. Once again we use the hierarchical capabilities of Oracle but this time we unpack instead of pack. The calculation of how many items are in the string is part of the trick here.

 

variable v1 varchar2(30)
exec begin :v1 := 'xyz,pdq,abc'; end;

SQL> select substr(','||:v1||','
  2               ,instr(','||:v1||',',',',1,rownum)+1
  3               ,instr(','||:v1||',',',',1,rownum+1)-instr(','||:v1||',',',',1,rownum)-1) avalue
  4  from dual
  5  connect by level <= length(:v1)-length(replace(:v1,','))+1
  6  /

AVALUE
----------------------------------
xyz
pdq
abc

3 rows selected.

 

The Function Method

 

create or replace type c_varchar2_30 is table of varchar2(30)
/

create or replace function unpack_delimited_string (string_p in varchar2) return c_varchar2_30 is
   c_varchar2_30_v c_varchar2_30 := c_varchar2_30();
begin
   for i in 1..nvl(length(string_p)-length(replace(string_p,','))+1,0) loop
      c_varchar2_30_v.extend;
      c_varchar2_30_v(c_varchar2_30_v.last) :=
            substr(','||string_p||','
                  ,instr(','||string_p||',',',',1,i)+1
                  ,instr(','||string_p||',',',',1,i+1)-instr(','||string_p||',',',',1,i)-1)
      ;
   end loop;
   return (c_varchar2_30_v);
end;
/
show errors

SQL> select *
  2  from table(cast(unpack_delimited_string('xyz,abc,pdq') as c_varchar2_30))
  3  /

COLUMN_VALUE
------------------------------
xyz
abc
pdq

3 rows selected.

 

Once again there are many variations of this theme mostly depending upon how you want the unpacked result returned. I like keeping things SQL ready so I choose the table type as my return type so I could get access to it via sql easily.

 

from: http://www.orafaq.com/node/2290

 

分享到:
评论

相关推荐

    Debugging and unpacking the NsPack 3.4 and 3.7 packer

    由SANS机构安全研究员编写的NsPack 3.4和3.7脱壳教程,使用OllyDbg调式并分析NsPack壳的程序,实现脱壳并分析其原理。

    The art of unpacking

    本文档主要介绍了脱壳的原理及应用,很有研究价值不仅仅是简单的脱壳教程

    解决git pull unpacking卡住.rar

    解决git pull的时候卡在unpacking 58%(57/97),网上搜了很多资料,都没有中文的详细解决案例,这里在这里上传一段总结,本来想写blog的。但因为没有分了,坑你们一分吧。但绝对实用。

    REA Unpacking Ebook

    国外的脱壳电子书,This ebook is a collection of unpacking tutorials, papers and documents gathered together by members of Reverse Engineering Association (REA).这是一本逆向工程相关的脱壳教程、论文和...

    snd-reversingwithlena-tutorials-qq664849305.rar

    逆向工程核心原理推荐的初学者入门必学视频。 A collection of tutorials ...39. Inlining a blowfish scheme in a packed & CRC protected dll + unpacking Asprotect SKE 2.2 40. Obfuscation and algorithm hiding

    Apress.PHP.7.Solutions.4th.Edition.rar

    using array shorthand syntax for list(), array dereferencing, and array unpacking with the splat operator. The problem is, you're not a programmer and the thought of writing code sends a chill up ...

    Microsoft.System.Center.Reporting.Cookbook.1782171800

    Gain access to real world solutions in the art and science of report planning and creation using System Center data Practical cookbook with recipes that will help you get the most out of Microsoft ...

    Pro PHP and jQuery(Apress,2ed,2016)

    types=1) and the new available data types, scalar type declarations for function arguments and return statements, constant arrays using define(), argument unpacking with the ... operator, integer ...

    python3.6.5参考手册 chm

    PEP 448 - Additional Unpacking Generalizations PEP 461 - percent formatting support for bytes and bytearray PEP 484 - Type Hints PEP 471 - os.scandir() function – a better and faster directory ...

    ZProtect 1.6 Unpacking(全面分析ZP 1.6)

    该技术资料由cektop大神(ZPfixer作者)编写,非常经典的ZProtect 1.6脱壳教程。

    unpacking Gie Protector 0.2 by Azmo

    A Shockwave Flash movie tutorial showing a method of unpacking Gie Protector 0.2.

    Python Cookbook, 2nd Edition

    Converting Between Unicode and Plain Strings Recipe 1.22. Printing Unicode Charactersto Standard Output Recipe 1.23. Encoding Unicode Data for XML and HTML Recipe 1.24. Making Some Strings Case...

    BlueHat IL 2019PPT汇总(13份).zip - 渗透测试

    PE-sieve:An Open-Source Process Scanner for Hunting and Unpacking Malware.pdf Practical Uses for Hardware-assisted Memory Visualization.pdf Supply Chain Security:If I were a Nation State....pdf ...

    09009938ZProtect-1.6-Unpacking.rar

    教程ZProtect-1.600脱壳教程,可跳过注册或无限重试,是比较完整的教程,方便,有用,图文,有需要的请下载使用。

    Arduino in Action

    You'll start with the basics—unpacking your board and using a simple program to make something happen. Then, you'l attempt progressively more complex projects as you connect Arduino to motors, LCD ...

    压缩工具 7-zip

    High compression ratio in 7z format with LZMA and LZMA2 compression Supported formats: Packing / unpacking: 7z, XZ, BZIP2, GZIP, TAR, ZIP and WIM Unpacking only: ARJ, CAB, CHM, CPIO, CramFS, DEB, DMG,...

    Python Tutorial 入门指南3.6英文版

    4.7.4. Unpacking Argument Lists 36 4.7.5. Lambda Expressions 37 4.7.6. Documentation Strings 38 4.7.7. Function Annotations 39 4.8. Intermezzo: Coding Style 39 5. Data Structures 40 5.1. More on Lists...

    android 7z 解压库

    High compression ratio in 7z format with LZMA and LZMA2 compression Supported formats: Packing / unpacking: 7z, XZ, BZIP2, GZIP, TAR, ZIP and WIM Unpacking only: AR, ARJ, CAB, CHM, CPIO, CramFS, DMG, ...

Global site tag (gtag.js) - Google Analytics