从函数返回结果集

从函数返回结果集

本文介绍了从函数返回结果集的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要从函数中返回一个结果集,并像使用普通表一样使用该结果集.

I need to return a resultset from function and work with this resultset just like with an ordinary table.

所以我需要以下内容:

select * from table(querydb('select * from dual'))

querydb函数应返回传递给它的查询的结果集.

The querydb function should return a resultset of a query passed to it.

可以在oracle中实现吗?

Can it be implemented in oracle?

将感谢您提供任何信息.

Would be grateful for any information.

推荐答案

如果需要结果集,而ref游标将不会使用名为sys.anydataset的数据类型.也就是说,您似乎想要的是流水线函数,但是当然需要一个常规的流水线函数,您需要定义输出结构,在您的情况下它不是静态的.

If you need a result set and a ref cursor won't do with a datatype called sys.anydataset. i.e what you seem to want is a pipelined function, but of course with a regular pipelined function you need to define the output structure, which in your case isn't static.

输入任何数据集.此类型使我们能够动态地动态生成类型(仅在硬解析时),以允许我们定义具有变化输出的流水线函数.

Enter anydataset. this type allows us to dynamically generate types on the fly (at hard parse time only) to allow us to define pipelined functions with varying outputs.

不幸的是,编码有点复杂.

The coding is a bit complex unfortunately.

首先,我们定义一个类型,该类型将处理传入的SQL语句.

To start with, we define a type that will do the processing of the passed in SQL statement.

SQL> create type dyn_pipeline as object
  2  (
  3    atype anytype,
  4
  5    static function ODCITableDescribe(rtype out anytype,
  6                                      stmt  in  varchar2)
  7      return number,
  8
  9    static function ODCITablePrepare(sctx      out dyn_pipeline,
 10                                     tf_info   in  sys.ODCITabfuncinfo,
 11                                     stmt      in  varchar2)
 12      return number,
 13
 14    static function ODCITableStart(sctx  in out dyn_pipeline,
 15                                   stmt  in     varchar2)
 16      return number,
 17
 18    member function ODCITablefetch(self  in out dyn_pipeline,
 19                                   nrows in     number,
 20                                  rws   out    anydataset)
 21      return number,
 22
 23    member function ODCITableClose(self in dyn_pipeline)
 24      return number
 25  );
 26  /

接下来,我们创建一个程序包规格,基本上就是您的querydb函数调用:

Next up, we create a package spec that will be basically your querydb function call:

SQL> create package pkg_pipeline
  2  as
  3
  4    /*
  5     * Global Types
  6     */
  7    -- Describe array.
  8    type dynamic_sql_rec is record(cursor    integer,
  9                                   column_cnt  pls_integer,
 10                                   description dbms_sql.desc_tab2,
 11                                   execute     integer);
 12    -- Meta data for the ANYTYPE.
 13    type anytype_metadata_rec is record(precision pls_integer,
 14                                        scale     pls_integer,
 15                                        length    pls_integer,
 16                                        csid      pls_integer,
 17                                        csfrm     pls_integer,
 18                                        schema    varchar2(30),
 19                                        type      anytype,
 20                                        name      varchar2(30),
 21                                        version   varchar2(30),
 22                                        attr_cnt  pls_integer,
 23                                        attr_type anytype,
 24                                        attr_name varchar2(128),
 25                                        typecode  pls_integer);
 26
 27
 28    /*
 29     * Global Variables
 30     */
 31    -- SQL descriptor.
 32    r_sql dynamic_sql_rec;
 33
 34    /*
 35     * function will run the given SQL
 36     */
 37    function querydb(p_stmt in varchar2)
 38      return anydataset pipelined using dyn_pipeline;
 39
 40  end pkg_pipeline;
 41  /

Package created.

那里的类型只会保存一些有关SQL结构本身的信息(我们将使用DBMS_SQL来描述输入的SQL,因为它具有从任何给定的SQL语句中获取列数,数据类型等的功能.

the types there will just hold some info about the SQL structure itself (we will be using DBMS_SQL to describe the input SQL as it has functions to get the number of columns, data types etc out of any given SQL statement.

主体类型是进行处理的地方:

The main type body is where the processing occurs:

SQL> create type body dyn_pipeline
  2  as
  3
  4    /*
  5     * DESC step. this will be called at hard parse and will create
  6     * a physical type in the DB Schema based on the select columns.
  7     */
  8    static function ODCITableDescribe(rtype out anytype,
  9                                      stmt  in  varchar2)
 10      return number
 11    is
 12
 13      /* Variables */
 14      -- Type to hold the dbms_sql info (description)
 15      r_sql   pkg_pipeline.dynamic_sql_rec;
 16      -- Type to create (has all the columns) of the sql query.
 17      t_anyt  anytype;
 18      -- SQL query that will be made up from the 2 passed in queries.
 19      v_sql   varchar2(32767);
 20
 21    begin
 22
 23      /*
 24       * Parse the SQL and describe its format and structure.
 25       */
 26      v_sql := replace(stmt, ';', null);
 27
 28      --  open, parse and discover all info about this SQL.
 29      r_sql.cursor := dbms_sql.open_cursor;
 30      dbms_sql.parse( r_sql.cursor, v_sql, dbms_sql.native );
 31      dbms_sql.describe_columns2( r_sql.cursor, r_sql.column_cnt, r_sql.description );
 32      dbms_sql.close_cursor( r_sql.cursor );
 33
 34      -- Start to create the physical type.
 35      anytype.BeginCreate( DBMS_TYPES.TYPECODE_OBJECT, t_anyt );
 36
 37      -- Loop through each attribute and add to the type.
 38      for i in 1 .. r_sql.column_cnt
 39      loop
 40
 41        t_anyt.AddAttr(r_sql.description(i).col_name,
 42                       case
 43                         when r_sql.description(i).col_type in (1,96,11,208)
 44                         then dbms_types.typecode_varchar2
 45                         when r_sql.description(i).col_type = 2
 46                         then dbms_types.typecode_number
 47                         when r_sql.description(i).col_type in (8,112)
 48                         then dbms_types.typecode_clob
 49                         when r_sql.description(i).col_type = 12
 50                         then dbms_types.typecode_date
 51                         when r_sql.description(i).col_type = 23
 52                         then dbms_types.typecode_raw
 53                         when r_sql.description(i).col_type = 180
 54                         then dbms_types.typecode_timestamp
 55                         when r_sql.description(i).col_type = 181
 56                         then dbms_types.typecode_timestamp_tz
 57                         when r_sql.description(i).col_type = 182
 58                         then dbms_types.typecode_interval_ym
 59                         when r_sql.description(i).col_type = 183
 60                         then dbms_types.typecode_interval_ds
 61                         when r_sql.description(i).col_type = 231
 62                         then dbms_types.typecode_timestamp_ltz
 63                       end,
 64                       r_sql.description(i).col_precision,
 65                       r_sql.description(i).col_scale,
 66                       r_sql.description(i).col_max_len,
 67                       r_sql.description(i).col_charsetid,
 68                       r_sql.description(i).col_charsetform );
 69      end loop;
 70
 71      t_anyt.EndCreate;
 72
 73      -- set the output type to our built type.
 74      ANYTYPE.BeginCreate(dbms_types.TYPECODE_TABLE, rtype);
 75      rtype.SetInfo(null, null, null, null, null, t_anyt,
 76                    dbms_types.TYPECODE_OBJECT, 0);
 77      rtype.EndCreate();
 78
 79      return ODCIConst.Success;
 80
 81    end ODCITableDescribe;
 82
 83
 84    /*
 85     * PREPARE step. Initialise our type.
 86     */
 87    static function ODCITableprepare(sctx      out dyn_pipeline,
 88                                     tf_info   in  sys.ODCITabfuncinfo,
 89                                     stmt      in  varchar2)
 90      return number
 91    is
 92
 93      /* Variables */
 94      -- Meta data.
 95      r_meta   pkg_pipeline.anytype_metadata_rec;
 96
 97    begin
 98
 99      r_meta.typecode := tf_info.rettype.getattreleminfo(
100                           1, r_meta.precision, r_meta.scale, r_meta.length,
101                           r_meta.csid, r_meta.csfrm, r_meta.type, r_meta.name
102                         );
103
104      sctx := dyn_pipeline(r_meta.type);
105      return odciconst.success;
106
107    end;
108
109
110    /*
111     * START step. this is where we execute the cursor prior to fetching from it.
112     */
113    static function ODCITablestart(sctx  in out dyn_pipeline,
114                                   stmt  in     varchar2)
115      return number
116    is
117
118      /* Variables */
119      r_meta pkg_pipeline.anytype_metadata_rec;
120      v_sql varchar2(32767);
121    begin
122
123      v_sql := replace(stmt, ';', null);
124      pkg_pipeline.r_sql.cursor := dbms_sql.open_cursor;
125      dbms_sql.parse(pkg_pipeline.r_sql.cursor, v_sql, dbms_sql.native);
126      dbms_sql.describe_columns2(pkg_pipeline.r_sql.cursor,
127                                 pkg_pipeline.r_sql.column_cnt,
128                                 pkg_pipeline.r_sql.description);
129
130      -- define all the columns found to let Oracle know the datatypes.
131      for i in 1..pkg_pipeline.r_sql.column_cnt
132      loop
133
134        r_meta.typecode := sctx.atype.GetAttrElemInfo(
135                             i, r_meta.precision, r_meta.scale, r_meta.length,
136                             r_meta.csid, r_meta.csfrm, r_meta.type, r_meta.name
137                           );
138
139        case r_meta.typecode
140          when dbms_types.typecode_varchar2
141          then
142            dbms_sql.define_column(pkg_pipeline.r_sql.cursor, i, '', 32767);
143          when dbms_types.typecode_number
144          then
145            dbms_sql.define_column(pkg_pipeline.r_sql.cursor, i, cast(null as number));
146          when dbms_types.typecode_date
147          then
148            dbms_sql.define_column(pkg_pipeline.r_sql.cursor, i, cast(null as date));
149          when dbms_types.typecode_raw
150          then
151            dbms_sql.define_column_raw(pkg_pipeline.r_sql.cursor, i, cast(null as raw), r_meta.length);
152          when dbms_types.typecode_timestamp
153          then
154            dbms_sql.define_column(pkg_pipeline.r_sql.cursor, i, cast(null as timestamp));
155          when dbms_types.typecode_timestamp_tz
156          then
157            dbms_sql.define_column(pkg_pipeline.r_sql.cursor, i, cast(null as timestamp with time zone));
158          when dbms_types.typecode_timestamp_ltz
159          then
160            dbms_sql.define_column(pkg_pipeline.r_sql.cursor, i, cast(null as timestamp with local time zone));
161          when dbms_types.typecode_interval_ym
162          then
163            dbms_sql.define_column(pkg_pipeline.r_sql.cursor, i, cast(null as interval year to month));
164          when dbms_types.typecode_interval_ds
165          then
166            dbms_sql.define_column(pkg_pipeline.r_sql.cursor, i, cast(null as interval day to second));
167          when dbms_types.typecode_clob
168          then
169            case pkg_pipeline.r_sql.description(i).col_type
170              when 8
171              then
172                dbms_sql.define_column_long(pkg_pipeline.r_sql.cursor, i);
173              else
174                dbms_sql.define_column(pkg_pipeline.r_sql.cursor, i, cast(null as clob));
175            end case;
176        end case;
177      end loop;
178
179      -- execute the SQL.
180      pkg_pipeline.r_sql.execute := dbms_sql.execute(pkg_pipeline.r_sql.cursor);
181
182      return odciconst.success;
183
184    end ODCITablestart;
185
186
187    /*
188     * FETCH step.
189     */
190    member function ODCITablefetch(self   in out dyn_pipeline,
191                                   nrows  in     number,
192                                   rws    out    anydataset)
193      return number
194    is
195
196      /* Variables */
197      -- Buffers to hold values.
198      v_vc_col       varchar2(32767);
199      v_num_col      number;
200      v_date_col     date;
201      v_raw_col      raw(32767);
202      v_raw_error    number;
203      v_raw_len      integer;
204      v_int_ds_col   interval day to second;
205      v_int_ym_col   interval year to month;
206      v_ts_col       timestamp;
207      v_tstz_col     timestamp with time zone;
208      v_tsltz_col    timestamp with local time zone;
209      v_clob_col     clob;
210      v_clob_offset  integer := 0;
211      v_clob_len     integer;
212      -- Metadata
213      r_meta  pkg_pipeline.anytype_metadata_rec;
214
215    begin
216
217      if dbms_sql.fetch_rows( pkg_pipeline.r_sql.cursor ) > 0
218      then
219
220        -- Describe to get number and types of columns.
221        r_meta.typecode := self.atype.getinfo(
222                             r_meta.precision, r_meta.scale, r_meta.length,
223                             r_meta.csid, r_meta.csfrm, r_meta.schema,
224                             r_meta.name, r_meta.version, r_meta.attr_cnt
225                           );
226
227        anydataset.begincreate(dbms_types.typecode_object, self.atype, rws);
228        rws.addinstance();
229        rws.piecewise();
230
231        -- loop through each column extracting value.
232        for i in 1..pkg_pipeline.r_sql.column_cnt
233        loop
234
235          r_meta.typecode := self.atype.getattreleminfo(
236                               i, r_meta.precision, r_meta.scale, r_meta.length,
237                               r_meta.csid, r_meta.csfrm, r_meta.attr_type,
238                               r_meta.attr_name
239                             );
240
241          case r_meta.typecode
242            when dbms_types.typecode_varchar2
243            then
244              dbms_sql.column_value(pkg_pipeline.r_sql.cursor, i, v_vc_col);
245              rws.setvarchar2(v_vc_col);
246            when dbms_types.typecode_number
247            then
248              dbms_sql.column_value(pkg_pipeline.r_sql.cursor, i, v_num_col);
249              rws.setnumber(v_num_col);
250            when dbms_types.typecode_date
251            then
252              dbms_sql.column_value(pkg_pipeline.r_sql.cursor, i, v_date_col);
253              rws.setdate(v_date_col);
254            when dbms_types.typecode_raw
255            then
256              dbms_sql.column_value_raw(pkg_pipeline.r_sql.cursor, i, v_raw_col,
257                 v_raw_error, v_raw_len);
258              rws.setraw(v_raw_col);
259            when dbms_types.typecode_interval_ds
260            then
261              dbms_sql.column_value(pkg_pipeline.r_sql.cursor, i, v_int_ds_col);
262              rws.setintervalds(v_int_ds_col);
263            when dbms_types.typecode_interval_ym
264            then
265              dbms_sql.column_value(pkg_pipeline.r_sql.cursor, i, v_int_ym_col);
266              rws.setintervalym(v_int_ym_col);
267            when dbms_types.typecode_timestamp
268            then
269              dbms_sql.column_value(pkg_pipeline.r_sql.cursor, i, v_ts_col);
270              rws.settimestamp(v_ts_col);
271            when dbms_types.typecode_timestamp_tz
272            then
273              dbms_sql.column_value(pkg_pipeline.r_sql.cursor, i, v_tstz_col);
274              rws.settimestamptz(v_tstz_col);
275           when dbms_types.typecode_timestamp_ltz
276           then
277              dbms_sql.column_value(pkg_pipeline.r_sql.cursor, i, v_tsltz_col);
278              rws.settimestampltz(v_tsltz_col);
279           when dbms_types.typecode_clob
280           then
281             case pkg_pipeline.r_sql.description(i).col_type
282               when 8
283               then
284                 loop
285                   dbms_sql.column_value_long(pkg_pipeline.r_sql.cursor, i, 32767, v_clob_offset,
286                                              v_vc_col, v_clob_len);
287                   v_clob_col := v_clob_col || v_vc_col;
288                   v_clob_offset := v_clob_offset + 32767;
289                   exit when v_clob_len < 32767;
290                 end loop;
291               else
292                 dbms_sql.column_value(pkg_pipeline.r_sql.cursor, i, v_clob_col);
293             end case;
294             rws.setclob(v_clob_col);
295          end case;
296        end loop;
297
298        rws.endcreate();
299
300      end if;
301
302      return ODCIConst.Success;
303
304    end;
305
306    /*
307     * CLOSE step. close the cursor.
308     */
309    member function ODCITableClose(self in dyn_pipeline)
310      return number
311    is
312
313
314    begin
315      dbms_sql.close_cursor( pkg_pipeline.r_sql.cursor );
316      pkg_pipeline.r_sql := null;
317      return odciconst.success;
318    end ODCITableClose;
319
320  end;
321  /

Type body created.

完成后,您可以像这样查询:

once this is done, you can query like:

SQL> select * from table(pkg_pipeline.querydb('select * from dual'));

D
-
X

SQL> select * from table(pkg_pipeline.querydb('select * from v$mystat where rownum <= 2'));

       SID STATISTIC#      VALUE
---------- ---------- ----------
       230          0          1
       230          1          1

这篇关于从函数返回结果集的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-01 16:45