Oracle:String Concatenation太长了

时间:2016-06-15 07:42:17

标签: sql string oracle concatenation

我在SQL下面作为视图的一部分。在其中一个模式中我得到" 字符串连接太长"错误,无法执行视图。

因此我尝试了 TO_CLOB(),现在VIEW没有抛出ERROR,但是它没有返回结果,它继续运行..

请建议....

SQL:

SELECT Iav.Item_Id Attr_Item_Id,
LISTAGG(La.Attribute_Name
    ||'|~|'
    || Lav.Attribute_Value
    ||' '
    || Lau.Attribute_Uom, '}~}') WITHIN GROUP (
  ORDER BY ICA.DISP_SEQ,LA.ATTRIBUTE_NAME) AS ATTR
    FROM Item_Attribute_Values Iav,
      Loc_Attribute_Values Lav,
      Loc_Attribute_Uoms Lau,
      Loc_Attributes La,
      (SELECT *
      FROM Item_Classification Ic,
        CATEGORY_ATTRIBUTES CA
      WHERE IC.DEFAULT_CATEGORY='Y'
      AND IC.TAXONOMY_TREE_ID  =CA.TAXONOMY_TREE_ID
      ) ICA
    WHERE IAV.ITEM_ID             =ICA.ITEM_ID(+)
    AND IAV.ATTRIBUTE_ID          =ICA.ATTRIBUTE_ID(+)
    AND Iav.Loc_Attribute_Id      =La.Loc_Attribute_Id
    AND La.Locale_Id              =1
    AND Iav.Loc_Attribute_Uom_Id  =Lau.Loc_Attribute_Uom_Id(+)
    AND Iav.Loc_Attribute_Value_Id=Lav.Loc_Attribute_Value_Id
    GROUP BY Iav.Item_Id;

错误:

ORA-01489: result of string concatenation is too long
01489. 00000 -  "result of string concatenation is too long"
*Cause:    String concatenation result is more than the maximum size.
*Action:   Make sure that the result is less than the maximum size.

4 个答案:

答案 0 :(得分:2)

您可以使用COLLECT() function将字符串聚合到一个集合中,然后使用User-Defined函数来连接字符串:

Oracle安装程序

CREATE TYPE stringlist IS TABLE OF VARCHAR2(4000);
/

CREATE FUNCTION concat_List(
  strings IN stringlist,
  delim   IN VARCHAR2 DEFAULT ','
) RETURN CLOB DETERMINISTIC
IS
  value CLOB;
  i     PLS_INTEGER;
BEGIN
  IF strings IS NULL THEN
    RETURN NULL;
  END IF;
  value := EMPTY_CLOB();
  IF strings IS NOT EMPTY THEN
    i := strings.FIRST;
    LOOP
      IF i > strings.FIRST AND delim IS NOT NULL THEN
        value := value || delim;
      END IF;
      value := value || strings(i);
      EXIT WHEN i = strings.LAST;
      i := strings.NEXT(i);
    END LOOP;
  END IF;
  RETURN value;
END;
/

<强>查询

SELECT Iav.Item_Id AS Attr_Item_Id,
       CONCAT_LIST(
         CAST(
           COLLECT(
             La.Attribute_Name || '|~|' || Lav.Attribute_Value ||' '|| Lau.Attribute_Uom
             ORDER BY ICA.DISP_SEQ,LA.ATTRIBUTE_NAME
           )
           AS stringlist
         ),
         '}~}'
       ) AS ATTR
FROM   your_table
GROUP BY iav.item_id;

答案 1 :(得分:1)

不幸的是,

LISTAGG限制为4000个字符。因此,您可能希望使用另一种方法来连接值。

无论如何......

很奇怪看到LISTAGG这是一个相当新的功能,并且容易出错的SQL1992连接。我建议你重写这个。表格是否正确加入?看起来很奇怪,Loc_AttributesLoc_Attribute_Values之间似乎没有关系。没有Loc_Attribute_Values一个Loc_Attribute_Id所以属性值与属性有关吗?很难相信没有这种关系。

此外:是否保证您的分类子查询不会为每个属性返回多个记录?

这是您的查询重写:

select 
  iav.item_id as attr_item_id,
  listagg(la.attribute_name || '|~|' || lav.attribute_value || ' ' || lau.attribute_uom,
   '}~}') within group (order by ica.disp_seq, la.attribute_name) as attr
from item_attribute_values iav
join loc_attribute_values lav 
       on lav.loc_attribute_value_id = iav.loc_attribute_value_id
       and lav.loc_attribute_id = iav.loc_attribute_id -- <== maybe?
join loc_attributes la 
       on la.loc_attribute_id = lav.loc_attribute_id 
       and la.loc_attribute_id = lav.loc_attribute_id -- <== maybe?
       and la.locale_id = 1
left join loc_attribute_uoms lau 
       on lau.loc_attribute_uom_id = iav.loc_attribute_uom_id
       and lau.loc_attribute_id = iav.loc_attribute_id -- <== maybe?
left join
(
  --  aggregation needed to get no more than one sortkey per item attribute?
  select ic.item_id, ca.attribute_id, min (ca.disp_seq) as disp_seq
  from item_classification ic
  join category_attributes ca on ca.taxonomy_tree_id = ic.taxonomy_tree_id
  where ic.default_category = 'y'
  group by ic.item_id, ca.attribute_id
) ica on ica.item_id = iav.item_id and ica.attribute_id = iav.attribute_id
group by iav.item_id;
嗯,你明白了;检查您的密钥并在必要时更改您的加入条件。也许这可以摆脱重复,所以LISTAGG必须连接较少的属性,结果甚至可以保持在4000个字符以内。

答案 2 :(得分:0)

我想你需要编写一个小函数来将字符串连接成CLOB,因为即使你最后TO_CLOB() LISTAGG,这可能也行不通。

这是一个示例函数,它接受一个SELECT-Statement(它必须只返回一个字符串列!)和一个分隔符,并将收集的值作为CLOB返回:

 CREATE OR REPLACE FUNCTION listAggCLob(p_stringSelect VARCHAR2
                                      , p_separator VARCHAR2)
   RETURN CLOB
AS
   cur SYS_REFCURSOR;
   s VARCHAR2(4000);
   c CLOB;   
   i INTEGER; 
BEGIN
   dbms_lob.createtemporary(c, FALSE);
   IF (p_stringSelect IS NOT NULL) THEN
      OPEN cur FOR p_stringSelect;
      LOOP
         FETCH cur INTO s;
         EXIT WHEN cur%NOTFOUND;
         dbms_lob.append(c, s || p_separator);
      END LOOP;
   END IF;
   i := length(c);
   IF (i > 0) THEN
      RETURN dbms_lob.substr(c,i-length(p_separator));
   ELSE
      RETURN NULL;
   END IF;
END;

此功能可用于f.e.像这样:

WITH cat AS (
   SELECT DISTINCT t1.category
     FROM lookup t1
   )
SELECT cat.category
     , listAggCLob('select t2.name from lookup t2 where t2.category = ''' || cat.category || '''', '|') allcategorynames  
  FROM cat;

答案 3 :(得分:0)

Xquery方法。 创建额外的类型或功能是不必要的。

with test_tab
     as (select object_name
           from all_objects
          where rownum < 1000)
   , aggregate_to_xml as (select xmlagg(xmlelement(val, object_name)) xmls from test_tab)
select xmlcast(xmlquery('for $row at $idx in ./*/text() return  if($idx=1) then $row else concat(",",$row)'
                passing aggregate_to_xml.xmls returning content) as Clob) as list_in_lob
  from aggregate_to_xml;