Преобразование regexp_substr (Oracle) в PostgreSQL

У меня есть запрос в Oracle SQL:

       select town_name, 
              regexp_substr(town_name, '[^A,]+', 1, 1) as c1,
              regexp_substr(town_name, '[^A,]+', 1, 2) as c2, 
              regexp_substr(town_name, '[^A,]+', 1, rownum) as c_rownum,
              rownum
          from epr_towns

Первые 2 строки результата:

VALGANNA        V   LG  V   1
VARANO BORGHI   V   R   R   2

Мне нужно получить такой же результат на PostgreSQL (для строки с regexp_substr(town_name, '[^A,]+', 1, rownum) as c_rownum), и я не знаю, как это сделать. Не могли бы вы помочь мне? Спасибо.


person Catalin Vladu    schedule 18.08.2015    source источник
comment
Ввод: имя_города (ВАЛГАННА для первой строки).   -  person Catalin Vladu    schedule 18.08.2015
comment
Фактические значения: VALGANNA и VARANO BORGHI (столбец 1). Столбцы 2..4 — это результаты, полученные с помощью regexp_substr в Oracle.   -  person Catalin Vladu    schedule 18.08.2015
comment
Предупреждение! Регулярное выражение формата '[^A,]+', обычно используемое для синтаксического анализа строк с разделителями, дает сбой, когда в списке есть элементы NULL. Убедитесь, что вы тщательно тестируете. Всегда ожидайте неожиданного! См. здесь для получения более подробной информации и улучшенного регулярного выражения. Я не знаю, как это будет переведено в Postgres: title="разделить значения, разделенные запятыми, на столбцы в оракуле"> stackoverflow.com/questions/31464275/   -  person Gary_W    schedule 18.08.2015


Ответы (2)


Здесь действительно две отдельные проблемы

  • замена rownum
  • замена regexp_substr на regexp_matches

Чтобы решить для rownum, используйте CTE (предложение WITH), чтобы добавить столбец, подобный rownum, в базовую таблицу.

regexp_matches работает немного иначе, чем Oracle regexp_substr. В то время как Oracle regexp_substr принимает n-е совпадение в качестве аргумента, PostgreSQL regexp_matches вернет все совпадения в виде функции с табличным значением. Таким образом, вам нужно обернуть вызов в подзапрос с ограничением/смещением, чтобы получить n-е совпадение. Кроме того, строки, возвращаемые regexp_substr, являются массивами, поэтому, предполагая, что в вашем регулярном выражении нет выражений в скобках, вам необходимо проиндексировать/разыменовать первый элемент в массиве.

Конечный результат выглядит так:

http://sqlfiddle.com/#!17/865ee/7

 with epr_towns_rn as (
    select town_name,
      row_number() over(order by town_name) as rn
  from epr_towns
)
select town_name,
   (select (regexp_matches(town_name, '[^A,]+', 'g'))[1] offset 0 limit 1) as c1,
   (select (regexp_matches(town_name, '[^A,]+', 'g'))[1] offset 1 limit 1) as c2,
   (select (regexp_matches(town_name, '[^A,]+', 'g'))[1] offset rn-1 limit 1)
     as c_rownum,
   rn
   from epr_towns_rn;

Если вам нужно только первое совпадение, вы можете пропустить аргумент 'g' и исключить ограничение/смещение из подзапроса, но вам все равно нужна оболочка подзапроса на случай отсутствия совпадения, чтобы имитировать regexp_substr, возвращающий null при отсутствии совпадения.

person wrschneider    schedule 05.07.2018

У меня нет таблицы, поэтому я использую generate, например:

   select town_name, 
          regexp_substr(town_name, '[^A,]+', 1, 1) as c1,
          regexp_substr(town_name, '[^A,]+', 1, 2) as c2, 
          regexp_substr(town_name, '[^A,]+', 1, dense_rank() over (order by town_name)) as c_rownum,
          dense_rank() over (order by c)
      from epr_towns

Я полагаю, вы ищете оконную функцию плотности_ранка?..

NB. всегда проще иметь скрипт SQL или исходный код

person Vao Tsun    schedule 18.08.2015
comment
Я искал плотности_rank() и преобразование regexp_substr() с 4 параметрами (для 2 параметров работает substring(town_name, '[^A,]+')) ) - person Catalin Vladu; 18.08.2015