Ошибка Oracle Sql Developer «слишком длинный строковый литерал» - PullRequest
7 голосов
/ 30 марта 2011

У меня есть следующий SQL, который я хотел бы запустить в Oracle SQL Developer на сервере Oracle 10g:

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('
  <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>
  ').extract('/theRange/theRow')))
)
SELECT *
FROM openedxml
WHERE age BETWEEN 30 AND 35;

Когда я пытаюсь запустить его, я получаю следующую ошибку:

Error at Command Line:1 Column:0 Error report: SQL Error: ORA-01704: string literal too long
01704. 00000 -  "string literal too long"
*Cause:    The string literal is longer than 4000 characters.
*Action:   Use a string literal of at most 4000 characters.
           Longer values may only be entered using bind variables.

Иногда мои строки будут намного длиннее 4000 символов.Любые идеи о том, как я могу обойти эту проблему?

Ответы [ 5 ]

11 голосов
/ 30 марта 2011

Вы не можете обойти это с "простым" SQL.(Но я был бы рад оказаться ошибочным)

Вам понадобится какой-то язык программирования (например, Java, хранимая процедура), чтобы справиться с этим.

Альтернативой является загрузка данных XML в таблицу (это можно сделать с помощью SQL * Loader) и использование значений столбца в вашем запросе.

Это одно из ограничений Oracleэто действительно сводит меня с ума.20 лет назад это могло быть несколько приемлемо, но сейчас ...

8 голосов
/ 12 апреля 2011

Вам нужно будет использовать CLOB в качестве входных данных для XMLTYPE () вместо VARCHAR.

Использование либо dbms_lob.loadclobfromfile для загрузки xml из файла, либо разбиение xml на 32000 символов и добавление в 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;
2 голосов
/ 21 октября 2011

Вы можете использовать обходной путь sql, используя insert / updates, где каждая часть, если меньше 4000 символов.

1 Делать вставку как вставку с первой частью - это sql литерал до 4000 символов 2 Выполните дополнительные части как обновление, объединяя предыдущие части со следующей частью, где следующая часть содержит до 4000 символов 3 Повторяйте шаг 2, пока не будет обновлен весь большой литерал sql.

Пример,

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>;
2 голосов
/ 31 марта 2011

Откуда взялся этот большой кусок XML?Я предполагаю, что вы не вводите его.

Обычно я смотрю на программу, которая читает исходный код и превращает его в CLOB.Это может быть скрипт perl / python / what на клиенте или серверная подпрограмма, которая извлекает значение из веб-сервера.

2 голосов
/ 30 марта 2011

Возможный обходной путь - использовать блоки PL / SQL:

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;

(полностью не проверено)

EDIT:

В качестве вставки вы можете попробовать:

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;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...