Oracle Sql Developer “string literal too long” error

前端 未结 5 1237
甜味超标
甜味超标 2020-12-19 06:18

I have the following SQL that I would like to run in Oracle SQL Developer against an Oracle 10g server:

WITH openedXml AS (
  SELECT extractvalue(column_va         


        
相关标签:
5条回答
  • 2020-12-19 06:59

    You will need to use a CLOB as the input to XMLTYPE() instead of a VARCHAR.

    Using either dbms_lob.loadclobfromfile to load the xml from a file, or by breaking up the xml into 32000 character chunks and appending to the CLOB.

    DECLARE
       xmlClob CLOB;
    BEGIN
    /* Build Clob here */
    
    WITH openedXml AS (
      SELECT extractvalue(column_value, '/theRow/First') FIRST,
             extractvalue(column_value, '/theRow/Last') LAST,
             to_number(extractvalue(column_value, '/theRow/Age')) Age
        FROM TABLE(XMLSequence(XMLTYPE(xmlClob).extract('/theRange/theRow')))
    )
    SELECT *
    FROM openedxml
    WHERE age BETWEEN 30 AND 35;
    END;
    
    0 讨论(0)
  • 2020-12-19 07:02

    Where does that great big chunk of XML come from ? I assume you are not typing it in.

    Generally I'd look at a program that reads the source and turns it into a CLOB. That might be a perl/python/whatever script on a client, or it might be a server side routine that pulls the value from a web-server.

    0 讨论(0)
  • 2020-12-19 07:10

    You can't get around this with "plain" SQL. (But I'd be glad to be proven wrong)

    You will need some kind of programming language (e.g. Java, Stored Procedure) to deal with this.

    An alternative is to upload the XML data into a table (can be done with SQL*Loader) and the use the column values in your query.

    This is one of the limitations of Oracle that is really driving me nuts. 20 years ago this might have been somewhat acceptable, but nowadays...

    0 讨论(0)
  • 2020-12-19 07:10

    You can use sql workaround using insert/updates where each part if less than 4000 chars.

    1 Do the insert as an insert with first part is the sql literal up to 4000 chars 2 Do the additional parts as an update concatenating the previous parts with the next part where the next part is up to 4000 chars 3 Repeat step 2 until all the large sql literal is updated.

    Example,

    Insert into
    test_large_literal (col1, col2)
    values
    (<key val>, <first part of large sql literal>);
    
    update
    test_large_literal
    set
    col2 = col2 || <second part large sql literal>
    where
    col1 = <key val>;
    ...
    ...
    update
    test_large_literal
    set
    col2 = col2 || <last part large sql literal>
    where
    col1 = <key val>;
    
    0 讨论(0)
  • 2020-12-19 07:11

    A possible workaround is to use PL/SQL blocks:

    DECLARE
      xml VARCHAR2(32000) := 
     '<theRange>
        <theRow><First>Bob</First><Last>Smith</Last><Age>30</Age></theRow>
        <theRow><First>Sue</First><Last>Jones</Last><Age>34</Age></theRow>
    ...
    ...
    ...
        <theRow><First>Tom</First><Last>Anderson</Last><Age>39</Age></theRow>
        <theRow><First>Ali</First><Last>Grady</Last><Age>45</Age></theRow>
      </theRange>';
    
      CURSOR C (p1 INTEGER, p2 INTEGER) IS
      SELECT * FROM (
        SELECT extractvalue(column_value, '/theRow/First') FIRST,
               extractvalue(column_value, '/theRow/Last') LAST,
               to_number(extractvalue(column_value, '/theRow/Age')) Age
          FROM TABLE(XMLSequence(XMLTYPE(xml).extract('/theRange/theRow'))))
      )
       WHERE age BETWEEN p1 AND p2;
    BEGIN
      FOR R IN C (30,35) LOOP
        dbms_output.put_line(R.First||', '||R.Last||', '||R.Age);
      END LOOP;
    END;
    

    (Completely untested)

    EDIT:

    As an insert, you could try:

    DECLARE
          xml VARCHAR2(32000) := 
         '<theRange>
            <theRow><First>Bob</First><Last>Smith</Last><Age>30</Age></theRow>
            <theRow><First>Sue</First><Last>Jones</Last><Age>34</Age></theRow>
        ...
        ...
        ...
            <theRow><First>Tom</First><Last>Anderson</Last><Age>39</Age></theRow>
            <theRow><First>Ali</First><Last>Grady</Last><Age>45</Age></theRow>
          </theRange>';
    BEGIN
      INSERT INTO temp_table(last,first,age)
      SELECT last, first, age FROM (
        SELECT extractvalue(column_value, '/theRow/First') FIRST,
               extractvalue(column_value, '/theRow/Last') LAST,
               to_number(extractvalue(column_value, '/theRow/Age')) Age
          FROM TABLE(XMLSequence(XMLTYPE(xml).extract('/theRange/theRow'))))
      )
       WHERE age BETWEEN 30 AND 35;
    END;
    
    0 讨论(0)
提交回复
热议问题