Я хочу извлечь строку после того, как конкретный символ существует в sql

У меня есть столбец с такими данными, как

SS ss_period (varchar) с1 01.01.2020-31.01.2020 с2 08.01.2019-31.08.2019 с3 АВС 04.01.2020-30.04.2020 с4 DEF GHI 04.01.2020-30.04.2020 с5 ABCDEFGHIJKLMNOP

как я могу получить такой результат

SS сс_период сс_период с1 01.01.2020 31.01.2020 с2 08.01.2019 31.08.2019 с3 04.01.2020 30.04.2020 с4 04.01.2020 30.04.2020 с5 нулевой нулевой

Я пытаюсь использовать strpos и split_part, но у меня это не работает. Я думаю, что я должен сначала удалить текст, кроме "-" и "/". но я не знаю, как это сделать.

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

Nikolaus 26.12.2020 13:51
ReactJs | Supabase | Добавление данных в базу данных
ReactJs | Supabase | Добавление данных в базу данных
Это и есть ваш редактор таблиц в supabase.👇
Понимание Python и переход к SQL
Понимание Python и переход к SQL
Перед нами лабораторная работа по BloodOath:
1
1
798
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Ответ принят как подходящий

Вы можете попробовать использовать сопоставление регулярных выражений и замены, чтобы выполнить тяжелую работу. Сначала убедитесь, что входное значение ss_period содержит две даты в ожидаемом формате, разделенном дефисом. Если это так, используйте замены регулярных выражений группами захвата, чтобы изолировать каждую дату. Если нет, то просто назначьте значение по умолчанию NULL.

SELECT
    ss,
    CASE WHEN ss_period ~ '.*\d+/\d+/\d+-\d+/\d+/\d+.*'
         THEN REGEXP_REPLACE(ss_period, '^.*(\d+/\d+/\d+)-.*$', '\1')
    END AS ss_period_start,
    CASE WHEN ss_period ~ '.*\d+/\d+/\d+-\d+/\d+/\d+.*'
         THEN REGEXP_REPLACE(ss_period, '^.*-(\d+/\d+/\d+).*$', '\1')
    END AS ss_period_end
FROM yourTable
ORDER BY ss;

Демо

Вы по-прежнему можете использовать функции STRPOS() и SPLIT_PART(), применяя CROSS и LEFT JOIN рекурсивно, например

SELECT t.ss, 
       SPLIT_PART(str, '-', 1) AS ss_period1, SPLIT_PART(str, '-', 2) AS ss_period2
  FROM t
  LEFT JOIN
  (
   SELECT ss, SPLIT_PART(ss_period, ' ', n) AS str
     FROM t
    CROSS JOIN generate_series(1, LENGTH(REGEXP_REPLACE(ss_period, '[^ ]', '', 'g'))+1) AS n
    WHERE STRPOS(SPLIT_PART(ss_period, ' ', n),'-') > 0 
   ) AS tt
    ON tt.ss = t.ss

Demo

Я рассматриваю это как проблему, состоящую из двух частей. Сначала найдите строку с диапазоном. Затем разделите его на две части.

В первой части regexp_match(), похоже, помогает. Для второго, split_part():

select t.*, split_part(v.rng, '-', 1), split_part(v.rng, '-', 2)
from t cross join lateral
     (values ((regexp_match(ss_period, '[0-9]{1,2}/[0-9]{1,2}/[0-9]{4}-[0-9]{1,2}/[0-9]{1,2}/[0-9]{4}'))[1])
     ) v(rng);

Здесь db<>рабочий пример.

Чтобы пойти в том же направлении, что и ответ Тима, вы можете использовать функцию regexp_match():

SELECT ss
     , (regexp_match(ss_period, '\d{1,2}/\d{1,2}/\d{4}'))[1] AS ss_period_start
     , right((regexp_match(ss_period, '-\d{1,2}/\d{1,2}/\d{4}'))[1], -1) AS ss_period_end
  FROM your_table ;

Другие вопросы по теме