【问题标题】:How to use LISTAGG with UDT in sql (oracle)?如何在 sql (oracle) 中使用 LISTAGG 和 UDT?
【发布时间】:2018-12-07 18:49:46
【问题描述】:

似乎 LISTAGG 功能不适用于 UDT,我该如何解决这个问题?

首先,看看我的sql:

create or replace type objtype as object(
    id int,
    col1 varchar2(30),
    col2 float
);

create table myTab(
    col1 objtype
);

insert into myTab values (objtype(1,'col1',10));
insert into myTab values (objtype(2,'col2',20));
insert into myTab values (objtype(3,'col3',3000));

select listagg(t.col1,', ') within group (order by 1) from myTab t;

我想要的是在一行中显示表格的每个元素,如下所示:

objtype(1,'col1',10) , objtype(2,'col2',20), objtype(3,'col3',3000)

但是我得到了这个错误:

报告错误-

错误的 SQL:ORA-00932:不一致的数据类型:预期 NUMBER 得到了 USER.OBJTYPE

  1. 00000 - “不一致的数据类型:预期的 %s 得到了 %s”

我应该使用其他功能吗?那是什么?

感谢您的回复。

【问题讨论】:

  • 您的集合没有自然的字符串表示形式 - 尽管您的客户端在查询表时可能会显示类似于您所看到的多行内容。如果是这样,这就是客户解释对象的方式;该表示在数据库中不可用,因此 listagg 无法使用它。如果您可以创建匹配的集合类型,您可能会得到最接近的对象集合;然后它的显示仍然取决于你的客户。

标签: sql oracle user-defined-types listagg


【解决方案1】:

1) 添加函数以生成对象的“文本”表示。

create or replace type objtype as object(
    id int,
    col1 varchar2(30),
    col2 float,
    member function toStr return varchar2
);

create or replace type body objtype is
    member function toStr return varchar2 is 
    begin 
      return 'objtype('||self.id||','||col1||','||col2||')';
    end;
end;

select listagg(t.col1.toStr(),', ') within group (order by 1) from myTab t;

2) Create User-defined Aggregates - 复杂而强大的

ImpAggr 正在实施自定义聚合机制。

create  or replace type  ImpAggr as object(
  list_of_object varchar2(32000), -- second highest value seen so far
  static function ODCIAggregateInitialize(sctx IN OUT ImpAggr) 
    return number,
  member function ODCIAggregateIterate(self IN OUT ImpAggr, 
    value IN objtype) return number,
  member function ODCIAggregateTerminate(self IN ImpAggr, 
    returnValue OUT varchar2, flags IN number) return number,
  member function ODCIAggregateMerge(self IN OUT ImpAggr, 
    ctx2 IN ImpAggr) return number
);
/

create or replace type body ImpAggr is 
static function ODCIAggregateInitialize(sctx IN OUT ImpAggr) 
return number is 
begin

   -- Aggregate Initialize
  sctx := ImpAggr(null);
  return ODCIConst.Success;
end;

member function ODCIAggregateIterate(self IN OUT ImpAggr, value IN objtype) return number is
begin
  -- Aggregate Iterate

  self.list_of_object :=list_of_object || ',objtype('||value.id||','||value.col1||','||value.col2||')';

  return ODCIConst.Success;
end;

member function ODCIAggregateTerminate(self IN ImpAggr, 
    returnValue OUT varchar2, flags IN number) return number is
begin
  -- retrun result list_of_object.
  returnValue := self.list_of_object;
  return ODCIConst.Success;
end;

member function ODCIAggregateMerge(self IN OUT ImpAggr, ctx2 IN ImpAggr) return number is
begin 
  -- merge content only if aggregation process gone in parallel execution
  self.list_of_object := ','||ctx2.list_of_object;
  return ODCIConst.Success;
end;
end;
/

创建聚合函数。

CREATE FUNCTION CustomAggregation (input objtype) RETURN varchar2 
PARALLEL_ENABLE AGGREGATE USING ImpAggr;

和用法。

select CustomAggregation(t.col1) from myTab t;

【讨论】:

    【解决方案2】:

    要将 listagg 与您的 UDT 一起使用,您需要以某种方式序列化您的数据。 从我的脑海中,您可以执行以下操作以从您的对象生成一个 XMLType,然后您可以在 XML 对象上使用 getStringVal() 函数 - 或者您可以向您的对象添加一个 toString 成员函数。

    例如:

    select listagg(xmltype(t.col1).getStringVal(),', ') within group (order by 1) from myTab t;
    ..... 
    <OBJTYPE><ID>1</ID><COL1>col1</COL1><COL2>10</COL2></OBJTYPE>, <OBJTYPE><ID>2</ID><COL1>col2</COL1><COL2>20</COL2></OBJTYPE>, <OBJTYPE><ID>3</ID><COL1>col3</COL1><COL2>3000</COL2></OBJTYPE>
    

    或者您也可以使用 XMLAGG(带或不带 getStringVal())

    select xmlagg(xmltype(t.col1)).getStringVal() from myTab t;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-07-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-07-25
      • 2020-12-31
      • 2021-11-08
      相关资源
      最近更新 更多