Получить фрагменты строки в двух столбцах в postgres

У меня есть таблица со строковым полем с именем info. В этом поле содержится некоторая информация о водителях и автомобилях, например «Водитель: Мэтт Автомобиль: Мустанг».

Есть ли способ получить запрос в два столбца, например: | Matt | Mustang |.

Я понятия не имею, что я могу сделать, может быть, регулярные выражения?


person Irish Wolf    schedule 08.08.2012    source источник
comment
Исправлены ли «Водитель» и «Автомобиль»? Я имею в виду, у вас есть именно эти два в каждом ряду?   -  person dezso    schedule 08.08.2012


Ответы (5)


WITH tbl(id, info) AS (
   VALUES
    (1::int, 'Driver: Matt Car: Mustang'::text)
   ,(2,      'Driver: Billy Car: Porsche')
   )
SELECT id
      ,split_part(info, ' ', 2) AS driver
      ,split_part(info, ' ', 4) As car
FROM   tbl;

Возвращает:

 id | driver  | car
----+---------+---------
  1 | Matt    | Mustang
  2 | Billy   | Porsche

На самом деле не имеет значения, какие строки вы получили вместо «Водитель» и «Автомобиль», если пробел есть, а имя находится справа от пробела.

person Erwin Brandstetter    schedule 09.08.2012

Если я не понял неправильно, вы могли бы использовать функцию string_to_array, чтобы разбить строку на элементы массива, а затем добраться до элементов по вашему желанию.

См. этот пост для получения дополнительной информации: Получить N-й элемент массива, возвращаемый функцией string_to_array()

person iso_9001_    schedule 09.08.2012
comment
Работал бы и красивее, чем у меня, но мое поле может возвращать информацию более-менее. Было бы намного проще, если бы я мог создавать отдельные поля для каждого значения:/ @iso_9001_ - person Irish Wolf; 09.08.2012

Лучше всего было бы написать функцию, которая берет одно из этих значений и возвращает запись с соответствующими столбцами на основе того, что она находит. Это позволит вам отладить вашу функцию с помощью операторов SELECT, прежде чем вы перейдете к заполнению новых столбцов (или таблиц). Затем вы можете использовать запрос в INSERT/SELECT или UPDATE ... FROM.

Вы можете использовать язык plpgsql для функций со строковыми функциями регулярных выражений PostgreSQL; но если вы свободно владеете perl или python, вы можете написать свою функцию на одном из этих языков.

person kgrittn    schedule 08.08.2012

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

  • Иметь намного, НАМНОГО более медленные запросы при запросе нескольких сериализованных подполей
  • Сложные запросы для обновления нескольких частей одного и того же поля
  • Чувство депрессии и отчаяния

Если бы мне пришлось иметь дело с такой базой данных, и я не мог бы изменить структуру базы данных, я бы, вероятно, в конечном итоге сделал много тяжелой работы в программном коде. Многие языки имеют лучшие (или, по крайней мере, более интуитивно понятные) инструменты обработки строк, чем SQL, и ваши преимущества в производительности от использования СУБД будут в лучшем случае незначительными при работе с сериализацией в любом случае.

Но если вам абсолютно необходимо сделать это в SQL, вы должны прочитать обработку строк в Postgres, расположенную здесь: http://www.postgresql.org/docs/9.1/static/functions-string.html

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

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

person Winfield Trail    schedule 08.08.2012
comment
Хорошо, но моя задача найти способ сделать это с помощью SQL. @sudowned - person Irish Wolf; 08.08.2012
comment
Тогда вам следует искать функции обработки строк Postgres: postgresql.org /docs/9.1/static/functions-string.html - person Winfield Trail; 09.08.2012

я сделал это:

select split_part(( case when
strpos(l.info,'Driver:') >= 1 then substr(l.info,strpos(l.info,'Driver:')+10, strpos(l.info, 'Водитель:')+9) end),E'\n',1) как водитель из гаража

Совсем не красиво, но возвращает данные в соответствии с моими потребностями

person Irish Wolf    schedule 09.08.2012