0

Как посчитать количество вхождений символа в значении varchar Oracle?

16

Заголовок: Как посчитать количество вхождений символа - в строке типа varchar2?

Тело вопроса:

Здравствуйте!

Я пытаюсь выяснить, как можно подсчитать количество вхождений символа - в строке типа varchar2 в базе данных Oracle.

Например, у меня есть следующая строка:

select XXX('123-345-566', '-') from dual;

Я хотел бы получить результат:

----------------------------------------
2

Кто-нибудь может подсказать, как это сделать? Заранее спасибо!

5 ответ(ов)

0

Вот как можно перевести ваш ответ на русский язык в стиле ответа на StackOverflow:

Для подсчета количества вхождений определенного символа в строке в Oracle можно использовать следующий запрос:

select length('123-345-566') - length(replace('123-345-566','-',null)) 
from dual;

Однако стоит отметить, что если строка содержит только тот символ, который вы хотите посчитать, данный запрос вернет значение NULL. Чтобы избежать этого и получить правильный ответ в любых случаях, стоит воспользоваться следующим вариантом:

select coalesce(length('123-345-566') - length(replace('123-345-566','-',null)), length('123-345-566'), 0) 
from dual;

В этом запросе функция coalesce позволяет обработать ситуацию, когда вы выполняете подсчет для пустой строки (то есть NULL, потому что length(NULL) возвращает NULL в Oracle). Конечный 0 в coalesce гарантирует, что в случае отсутствия символов в строке результат будет равен 0, а не NULL.

0

Вот идея: попробуйте заменить все символы, которые не являются дефисом, на пустую строку. Затем посчитайте, сколько дефисов осталось.

Вот пример запроса на SQL, который осуществляет это:

select length(regexp_replace('123-345-566', '[^-]', '')) from dual

Этот запрос заменяет все символы, кроме дефисов, на пустую строку, а затем считает длину оставшейся строки, которая соответствует количеству дефисов в исходной строке.

0

Вы столкнулись с проблемой, которая довольно распространена при использовании функции REGEXP_COUNT в Oracle. Давайте разберёмся, почему ваша функция возвращает неверное количество совпадений.

Функция REGEXP_COUNT действительно может не учитывать повторяющиеся совпадения, особенно в случае перекрывающихся подстрок. Например, в строке 'bbaaaacc' подстрока 'aa' встречается три раза, но из-за того, что REGEXP_COUNT не считает пересекающиеся совпадения, он возвращает 2.

Ваше решение с использованием пользовательской функции EXPRESSION_COUNT выглядит многообещающе. Давайте кратко рассмотрим его.

Объяснение функции

Функция EXPRESSION_COUNT проходит через строку, сравнивая каждую подстроку заданной длины с искомой фразой. Если совпадение найдено, счётчик увеличивается. Таким образом, вы обрабатываете строку в цикле, сдвигая её на один символ в каждой итерации.

Возможные улучшения

  1. Сокращение количества операций: Вместо двукратного вызова LENGTH можно сохранить длину строки в переменной.

  2. Условие выхода: Ваше условие выхода можно упростить, проверяя только одно условие в конце цикла.

  3. Прямое использование INSTR: Можно оптимизировать функцию используя функцию INSTR, чтобы находить позицию следующего вхождения строки.

Вот пример улучшенной версии вашей функции:

CREATE OR REPLACE FUNCTION EXPRESSION_COUNT( pEXPRESSION VARCHAR2, pPHRASE VARCHAR2 ) RETURN NUMBER AS
  vRET NUMBER := 0;
  vSTART NUMBER := 1;
BEGIN
  LOOP
    vSTART := INSTR(pEXPRESSION, pPHRASE, vSTART);
    EXIT WHEN vSTART = 0; -- Если не найдено, выходим из цикла
    vRET := vRET + 1; -- Увеличиваем счётчик
    vSTART := vSTART + 1; -- Сдвигаем на 1 символ для поиска следующего вхождения
  END LOOP;
  RETURN vRET;
END;

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

Если вы используете эту функцию, проверьте результаты:

SELECT EXPRESSION_COUNT('336,14,3,3,11,0,', ',3,') FROM dual;
SELECT EXPRESSION_COUNT('bbaaaacc', 'aa') FROM dual;

Это должно вернуть Вам 2 и 3 соответственно, что соответствует ожидаемым значениям.

0

Ваш запрос для подсчета количества символов '-' в строке '123-345-566' выглядит корректно. Давайте разберем его по частям.

Вы используете функцию LENGTH для определения длины исходной строки и длины строки без символов '-'. Вычитая вторую длину из первой, вы получаете количество символов '-', которые были удалены.

Вот ваш запрос:

SELECT LENGTH('123-345-566') - LENGTH(REPLACE('123-345-566', '-', '')) FROM DUAL;
  1. LENGTH('123-345-566') возвращает длину исходной строки, которая равна 11.
  2. REPLACE('123-345-566', '-', '') заменяет все символы '-' на пустую строку, в результате чего получаем '123345566'.
  3. LENGTH(REPLACE('123-345-566', '-', '')) возвращает длину строки без '-' — в данном случае это 9.
  4. Вычитая 9 из 11, мы получаем 2.

Таким образом, ваш запрос вернет значение 2, что и является количеством символов '-' в строке '123-345-566'.

Если у вас есть дополнительные вопросы или вам нужна помощь с другими SQL-запросами, не стесняйтесь задавать!

0

Вы можете попробовать следующий запрос:

select count(distinct pos) from
(select instr('123-456-789', '-', level) as pos from dual
  connect by level <= length('123-456-789'))
where nvl(pos, 0) != 0

Этот запрос корректно подсчитывает количество вхождений разделителя '-' в строке '123-456-789'.

Для подсчета количества вхождений подстроки 'aa' в строке 'bbaaaacc' можно использовать аналогичный запрос:

select count(distinct pos) from
(select instr('bbaaaacc', 'aa', level) as pos from dual
  connect by level <= length('bbaaaacc'))
where nvl(pos, 0) != 0

Этот запрос подсчитает количество уникальных позиций, где встречается 'aa' в строке 'bbaaaacc'.

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь