Nano Hash - криптовалюты, майнинг, программирование

Как выбрать подстроку в оракуле?

У меня есть сценарий, в котором мои данные выглядят примерно так:

Глава 18 Раздел 10 Раздел 16

  • Случай 1: я хочу выбрать главу 18 из приведенной выше строки.
  • Случай 2: я хочу выбрать Unit 10 из приведенной выше строки.
  • Случай 3: я хочу выбрать раздел 16 из приведенной выше строки.
10.09.2014

  • числа постоянны? может быть chapter 45 unit 145 sect 2? Как насчет учета регистра? 10.09.2014
  • Что вы пробовали? На stackoverflow есть много-много подобных вопросов. 10.09.2014

Ответы:


1

Использование подстроки:

declare
  l_start number := DBMS_UTILITY.get_cpu_time;
begin
for i in (
with t as (
  select 'Chapter ' || level || ' Unit ' || level || ' Sect ' || level  d from dual connect by rownum < 100000
)
select substr(d, 1, instr(d, ' ', 1, 2) - 1) chapter
     , substr(d, 
          instr(d, ' ', 1, 2), 
          instr(d, ' ', 1, 4) - instr(d, ' ', 1, 2)
       ) unit
     , substr(d, 
          instr(d, ' ', 1, 4), 
          length(d) - instr(d, ' ', 1, 4) + 1
       ) sect 
  from t
)
loop
  null;
end loop;
 DBMS_OUTPUT.put_line((DBMS_UTILITY.get_cpu_time - l_start) || ' hsec');
end;

126 hsec

Использование регулярного выражения:

declare
  l_start number := DBMS_UTILITY.get_cpu_time;
begin
for i in (
with t as (
  select 'Chapter ' || level || ' Unit ' || level || ' Sect ' || level  d from dual connect by rownum < 100000
)
select regexp_substr(d, 'Chapter [0-9]*') chapter
     , regexp_substr(d, 'Unit [0-9]*') unit
     , regexp_substr(d, 'Sect [0-9]*') sect 
  from t
)
loop
  null;
end loop;
 DBMS_OUTPUT.put_line((DBMS_UTILITY.get_cpu_time - l_start) || ' hsec');
end;

190 hsec

Таким образом, решение с регулярным выражением медленнее, но оно более читабельно, на вашем месте я бы использовал регулярное выражение.

10.09.2014
  • Это совершенно неправильный тестовый пример. В вашем запросе REGEXP не используется столбец «d», скорее вы просто жестко запрограммировали «Глава 18, раздел 10, раздел 16». Просто замените его столбцом d и увидите разницу. Я отредактирую свой пост, чтобы добавить ваш тестовый пример, чтобы подтвердить свое утверждение о том, что REGEXP будет медленнее и будет потреблять больше ресурсов. 11.09.2014
  • В новом обновлении, возможно, вы скопировали и вставили код substr в регулярное выражение, поэтому оба кода являются одинаковыми. Возможно, вам придется редактировать снова. 12.09.2014

  • 2

    Я бы использовал REGEXP_SUBSTR (документацию) с правильной обычной выражения. Например:

    select regexp_substr('Chapter 18 Unit 10 Sect 16', 'Chapter \d*') from dual;
      --Will return: Chapter 18
    select regexp_substr('Chapter 18 Unit 10 Sect 16', 'Unit \d*') from dual;
      --Will return: Unit 10
    select regexp_substr('Chapter 18 Unit 10 Sect 16', 'Sect \d*') from dual;
      --Will return: Sect 16
    

    Конечно, если вы храните Chapter xx Unit yy Sect zz строк в таблице, вы просто используете такой запрос для получения нескольких результатов:

    select regexp_substr(info_column, 'Chapter \d*') from mytable;
    

    Вы можете заменить \d на [0-9] или [[:digit:]]

    SQLfiddle

    10.09.2014
  • Нет проблем с регулярными выражениями, пока вы не столкнетесь с проблемами с высоким потреблением ресурсов ЦП. Я бы предпочел использовать старый SUBSTR для такого простого требования. 10.09.2014
  • Конечно, я бы предложил обычный substr, если значения в рассматриваемой строке всегда будут двузначными. 10.09.2014
  • Смотрите мое обновление. Я показал, что REGEXP медленнее, используя тестовый пример zaratustra. Его тестовый пример был неправильным, и после исправления он показывает новое время выполнения, чтобы доказать этот факт. 11.09.2014

  • 3

    Я бы использовал старый SUBSTR, а не REGEXP. Поскольку REGEXP будет занимать слишком много ресурсов ЦП.

    Ваше требование довольно простое.

    Для данных как Chapter 18 Unit 10 Sect 16, если вы хотите, чтобы Глава 18 была выводом:

    Просто выполните:

    Select substr(column, 1, 10) from table

    Аналогично можно сделать и для других выходов.

    Редактировать: Ребята, некоторые из вас могут подумать, почему я акцентирую внимание на старом добром SUBSTR, а не на REGEXP. Просто включите трассировку и посмотрите на вывод трассировки. Я согласен, что в более новых версиях Oracle значительно улучшила REGEXP. Но до настоящего времени я не видел случая, чтобы я остался доволен. Я могу ошибаться, поэтому, если у кого-то есть тестовый пример, я бы очень хотел его увидеть. Это было бы хорошим уроком для всех нас.

    Неправильное обновление, чтобы показать приведенный выше тестовый пример о РЕГУЛЯРНОМ ВЫРАЖЕНИИ быстрее, чем SUBSTR + INSTR!

    РЕГУЛЯРНОЕ ВЫРАЖЕНИЕ:

    SQL> DECLARE
      2      l_start NUMBER := dbms_utility.get_cpu_time;
      3  BEGIN
      4      FOR i IN (WITH t
      5                     AS (SELECT 'Chapter '
      6                                || LEVEL
      7                                || ' Unit '
      8                                || LEVEL
      9                                || ' Sect '
     10                                || LEVEL d
     11                         FROM   dual
     12                         CONNECT BY ROWNUM < 100000)
     13                SELECT Regexp_substr(d, 'Chapter [0-9]*') chapter,
     14                       Regexp_substr(d, 'Unit [0-9]*')    unit,
     15                       Regexp_substr(d, 'Sect [0-9]*')    sect
     16                 FROM   t) LOOP
     17          NULL;
     18      END LOOP;
     19
     20      dbms_output.Put_line('time taken by REGULAR EXPRESSION : '
     21                           || ( dbms_utility.get_cpu_time - l_start )
     22                           || ' hsec');
     23  END;
     24
     25  /
    time taken by REGULAR EXPRESSION : 61 hsec
    
    PL/SQL procedure successfully completed.
    

    SUBSTR + INSTR:

    SQL> DECLARE
      2      l_start NUMBER := dbms_utility.get_cpu_time;
      3  BEGIN
      4      FOR i IN (WITH t
      5                     AS (SELECT 'Chapter '
      6                                || LEVEL
      7                                || ' Unit '
      8                                || LEVEL
      9                                || ' Sect '
     10                                || LEVEL d
     11                         FROM   dual
     12                         CONNECT BY ROWNUM < 100000)
     13                SELECT Substr(d, 1, Instr(d, ' ', 1, 2) - 1)
     14                       chapter,
     15                       Substr(d, Instr(d, ' ', 1, 2),
     16                       Instr(d, ' ', 1, 4) - Instr(d,
     17                       ' ', 1, 2))
     18                       unit,
     19                       Substr(d, Instr(d, ' ', 1, 4), Length(d) - Instr(d, ' ', 1,
     20                                                                  4)
     21                                                      + 1)
     22                       sect
     23                 FROM   t) LOOP
     24          NULL;
     25      END LOOP;
     26
     27      dbms_output.Put_line('time taken by SUBSTR + INSTR : '
     28                           || ( dbms_utility.get_cpu_time - l_start )
     29                           || ' hsec');
     30  END;
     31
     32  /
    time taken by SUBSTR + INSTR : 28 hsec
    
    PL/SQL procedure successfully completed.
    

    Итак, ясно видно, что SUBSTR + INSTR заняло вдвое меньше времени, чем РЕГУЛЯРНОЕ ВЫРАЖЕНИЕ.

    10.09.2014
  • Пока числа всегда двухзначные, а элементы всегда в таком порядке. Не уверен, что это ясно из вопроса. (что-то вроде... всегда немного беспокоит!). Regex является более гибким, но, очевидно, потенциально затратным. 10.09.2014
  • Взгляните на мой ответ. REGEXP значительно превосходит SUBSTR + INSTR. 10.09.2014
  • @zaratustra, конечно, позвольте мне взглянуть и проверить. 10.09.2014
  • @ Алекс, я не ненавижу регулярные выражения. Просто мне не нравится их производительность в пакетных процессах или в системах OLTP. Они так много потребляют ресурсов. 10.09.2014

  • 4

    Моя версия, полезная, когда длина данных НЕ фиксирована.! Это может быть немного общим

    Последний аргумент regexp_substr фактически возвращает соответствующий результат case!

    SELECT level as case ,
           regexp_substr('Chapter 180 Unit 10 Sect 16 World 100', '\w* \d*( )*',1,level) as result
    FROM dual
      CONNECT BY level <= CEIL(regexp_count('Chapter 180 Unit 10 Sect 16 World 100',' ')/2)
    

    Результат:

          CASE RESULT
    ---------- ------------------------
             1 Chapter 180
             2 Unit 10
             3 Sect 16
             4 World 100
    

    Демонстрация скрипта

    10.09.2014
  • Они могут быть несовместимы с транзакциями OLTP, но они действительно гибкие! 11.09.2014
  • Гибкий, да. Жадный до ресурсов, да :-) 11.09.2014
  • Да Бро! обычно такие требования могут быть в DW. Я часто использую его. Не в сети. И мой оракул размещен на EXADATA .. злоупотреблении ресурсами, о котором мы никогда не слышали от DBA .. мы видим только при использовании: p 11.09.2014
  • Счастливчик, который попал на EXADATA, лол! Во всяком случае, меня беспокоит только то, что ответ, помеченный как правильный, демонстрирует неправильный тестовый пример. 11.09.2014
  • Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

    Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
    В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..