Я знаю, что на этот вопрос в какой-то степени ответили PHP и MYSQL, но мне было интересно, может ли кто-нибудь научить меня простейшему подходу к разделению строки (с разделителями-запятыми) на несколько строк в Oracle 10g (предпочтительно) и 11g.
Таблица выглядит следующим образом:
Name | Project | Error
108 test Err1, Err2, Err3
109 test2 Err1
Я хочу создать следующее:
Name | Project | Error
108 Test Err1
108 Test Err2
108 Test Err3
109 Test2 Err1
Я видел несколько потенциальных решений для стека, однако они учитывали только один столбец (являющийся строкой, разделенной запятыми). Любая помощь будет принята с благодарностью.
REGEXP
,XMLTABLE
иMODEL
п, см Split , разделенных запятыми строк в таблице с помощью Oracle SQLОтветы:
Это может быть улучшенный способ (также с regexp и connect by):
РЕДАКТИРОВАТЬ : Вот простое (например, «не углубленное») объяснение запроса.
length (regexp_replace(t.error, '[^,]+')) + 1
используетсяregexp_replace
для удаления всего, что не является разделителем (в данном случае запятой), иlength +1
для получения количества элементов (ошибок).select level from dual connect by level <= (...)
Использует иерархический запрос , чтобы создать столбец с увеличением числа совпадений найдено, от 1 до общего числа ошибок.Предварительный просмотр:
table(cast(multiset(.....) as sys.OdciNumberList))
выполняет кастинг типов оракулов.cast(multiset(.....)) as sys.OdciNumberList
Преобразует несколько семейств (один сборник для каждой строки в исходном наборе данных) в единый набор чисел, OdciNumberList.table()
Функция превращает коллекцию в результирующий.FROM
без соединения создает перекрестное соединение между вашим набором данных и мультимножеством. В результате строка в наборе данных с 4 совпадениями будет повторяться 4 раза (с увеличением числа в столбце с именем "column_value").Предварительный просмотр:
trim(regexp_substr(t.error, '[^,]+', 1, levels.column_value))
использует вcolumn_value
качестве параметра nth_appearance / ocurrence дляregexp_substr
.t.name, t.project
в качестве примера) для упрощения визуализации.Некоторые ссылки на документы Oracle:
источник
'[^,]+'
для синтаксического анализа строк не возвращает правильный элемент, если в списке есть нулевой элемент. См. Здесь для получения дополнительной информации: stackoverflow.com/questions/31464275/…regexp_count(t.error, ',')
вместоlength (regexp_replace(t.error, '[^,]+'))
, что может принести еще одно улучшение производительностирегулярные выражения - замечательная штука :)
источник
Name
s связана, что можно увидеть, если удалитьdistinct
. К сожалению добавлениеand Name = prior Name
вconnect by
пункт причинORA-01436: CONNECT BY loop in user data
.ORA-01436
ошибки, добавивAND name = PRIOR name
(или любой другой первичный ключ) иAND PRIOR SYS_GUID() IS NOT NULL
Есть огромная разница между двумя нижеприведенными:
Если вы не ограничиваете строки, то предложение CONNECT BY создаст несколько строк и не даст желаемого результата.
Помимо регулярных выражений , есть еще несколько альтернатив:
Настроить
Использование XMLTABLE :
Использование предложения MODEL :
источник
('"' || REPLACE(text, ',', '","') || '"')
а скобки не снимаются? Документы Oracle ([ docs.oracle.com/database/121/SQLRF/functions268.htm ) мне не понятны. Это такXQuery_string
?Еще пара примеров того же:
Также можно использовать DBMS_UTILITY.comma_to_table и table_to_comma: http://www.oracle-base.com/articles/9i/useful-procedures-and-functions-9i.php#DBMS_UTILITY.comma_to_table
источник
comma_to_table()
работает только с токенами, которые соответствуют соглашениям об именах объектов базы данных Oracle. Он будет швырять веревку,'123,456,789'
например.Я хотел бы предложить другой подход с использованием табличной функции PIPELINED. Это несколько похоже на метод XMLTABLE, за исключением того, что вы предоставляете свою собственную функцию для разделения строки символов:
Полученные результаты:
Проблема с этим типом подхода заключается в том, что оптимизатор часто не знает количество элементов табличной функции, и ему приходится делать предположения. Это может быть потенциально вредным для ваших планов выполнения, поэтому это решение можно расширить для предоставления статистике выполнения оптимизатору.
Вы можете увидеть эту оценку оптимизатора, запустив EXPLAIN PLAN для запроса выше:
Несмотря на то, что в коллекции всего 3 значения, оптимизатор оценил для нее 8168 строк (значение по умолчанию). Сначала это может показаться несущественным, но оптимизатору этого может быть достаточно, чтобы выбрать неоптимальный план.
Решение состоит в том, чтобы использовать расширения оптимизатора для предоставления статистики для коллекции:
Тестирование полученного плана выполнения:
Как видите, количество элементов в приведенном выше плане больше не является предполагаемым значением 8196. Это по-прежнему неправильно, потому что мы передаем функции столбец вместо строкового литерала.
Для более точной оценки в данном конкретном случае потребуется некоторая настройка кода функции, но я думаю, что здесь в значительной степени объясняется общая концепция.
Функция str2tbl, используемая в этом ответе, была первоначально разработана Томом Кайтом: https://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:110612348061
Концепцию связывания статистики с типами объектов можно подробнее изучить, прочитав эту статью: http://www.oracle-developer.net/display.php?id=427
Описанная здесь техника работает в 10g +.
источник
REGEXP_COUNT не было добавлено до Oracle 11i. Вот решение Oracle 10g, заимствованное из решения Art.
источник
Начиная с Oracle 12c вы могли использовать
JSON_TABLE
иJSON_ARRAY
:И запрос:
Вывод:
db <> демо скрипта
источник
Вот альтернативная реализация с использованием XMLTABLE, которая позволяет выполнять приведение к различным типам данных:
... или если ваши строки с разделителями хранятся в одной или нескольких строках таблицы:
источник
Хочу добавить еще один метод. Здесь используются рекурсивные запросы, чего я не видел в других ответах. Он поддерживается Oracle с 11gR2.
Это довольно гибко с символом разделения. Просто поменяйте его в
INSTR
звонках.источник
Без использования connect by или regexp :
источник
У меня была такая же проблема, и мне помог xmltable:
ВЫБРАТЬ id, обрезать (COLUMN_VALUE) текст FROM t, xmltable (('"' || REPLACE (text, ',', '", "') || '"'))
источник
В Oracle 11g и более поздних версиях вы можете использовать рекурсивный подзапрос и простые строковые функции (которые могут быть быстрее, чем регулярные выражения и коррелированные иерархические подзапросы):
Настройка Oracle :
Запрос :
Выход :
db <> скрипка здесь
источник
Я использовал функцию DBMS_UTILITY.comma_to _table, которая фактически работает с кодом следующим образом
я использовал свои собственные имена таблиц и столбцов
источник
comma_to_table()
работает только с токенами, которые соответствуют соглашениям об именах объектов базы данных Oracle. Он будет швырять веревку,'123,456,789'
например.