Получение последнего слова из строки Postgres, декларативно - PullRequest
18 голосов
/ 01 июня 2010

[РЕДАКТИРОВАТЬ] оригинальное название этого вопроса было "Получение последнего элемента массива Postgres, декларативно"

Как получить последний элемент массива в Postgres?

Мне нужно сделать это декларативно, так как я хочу использовать его в качестве критерия ORDER BY. Я бы не хотел создавать для него специальную функцию PGSQL: чем меньше изменений в базе данных, тем лучше в этом случае.

На самом деле, я хочу отсортировать по последнему слову определенного столбца, содержащего несколько слов. Смена модели здесь не вариант.

Другими словами, я хочу подтолкнуть Ruby sort_by {|x| x.split[-1]} на уровень базы данных. Я могу разбить значение на массив слов с помощью функций Postgres string_to_array или regexp_split_to_array, тогда как получить его последний элемент?

Ответы [ 8 ]

32 голосов
/ 25 января 2011

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

Вы можете пропустить посредника и получить последний элемент напрямую:

SELECT regexp_replace('foo bar baz', '^.* ', '')

Результат:

baz
13 голосов
/ 01 июня 2010

Использовать array_upper () :

SELECT array_upper(ARRAY[1,2,5,6], 1);
9 голосов
/ 06 августа 2012

В: я хочу отсортировать по последнему слову определенного столбца

При работе с фактическим массивом text (не строкой) используйте array_upper() в индексе.

Демонстрация для одномерного массива

WITH x(a) AS (
    VALUES
       ('{zoo, zar, zaz}'::text[])
      ,('{3,4,5,6}')
      ,('{foo, bar, baz}')
    )
SELECT *
FROM   x
ORDER  BY <b>a[array_upper(a, 1)]</b>;

Демонстрация для 2-мерного массива

WITH x(a) AS (
    VALUES
       ('{{zoo, zar, zaz}
         ,{4,5,6}
         ,{14,15,16}
         ,{foo, bar, zzzaz}}'::text[])
      ,('{{zoo, zar, baz}
         ,{4,5,6}
         ,{14,15,16}
         ,{foo, bar, aaaaz}}'::text[])
    )
SELECT *
FROM   x
ORDER  BY <b>a[array_upper(a, 1)][array_upper(a, 2)]</b>;
3 голосов
/ 26 августа 2015

Вы можете сделать следующее:

SELECT (ARRAY[1,8,3,7])[array_upper(ARRAY[1,8,3,7], 1)];

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

1 голос
/ 22 августа 2014

ОБНОВЛЕНИЕ: вопрос был отредактирован, поэтому я обновляю свой ответ.

Вы также можете использовать array_upper () для возврата самого элемента (а не только его индекса):

SELECT arr[array_upper(arr, 1)] FROM (SELECT ARRAY[1,2,3,6] AS arr) AS t

Итак, ответ:

SELECT arr[array_upper(arr, 1)] FROM (SELECT string_to_array('one two three', ' ') AS arr) AS t

результат: 'three'

1 голос
/ 01 июня 2010

Отредактировано: ЭТО НЕПРАВИЛЬНО - СМ. НИЖЕ ДЛЯ ПРАВИЛЬНОГО ОТВЕТА -

Полагаю, вы должны использовать array_length():

SELECT string_to_array('hi guys, welcome', ' ') AS arr INTO temparr;
SELECT * FROM temparr;
         arr
----------------------
 {hi,"guys,",welcome}

SELECT arr[array_length(arr,1)] FROM temparr;
   arr
---------
 welcome

Чтобы использовать это декларативно, (на лету) вы можете создать небольшую функцию SQL:

CREATE FUNCTION last_elem (text[]) RETURNS text AS $$
 SELECT $1[array_length($1,1)];
$$ LANGUAGE SQL;


 select last_elem(string_to_array('hi guys, welcome', ' '));
 last_elem
-----------
 welcome

------- РЕДАКТИРОВАНИЕ - ПРАВИЛЬНЫЙ СЛЕДУЮЩИЙ ОТВЕТ ----------------------

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

Тогда правильный путь - с array_upper()

CREATE FUNCTION last_elem (text[]) RETURNS text AS $$
 SELECT $1[array_upper($1,1)];
$$ LANGUAGE SQL;


 select last_elem(string_to_array('hi guys, welcome', ' '));
 last_elem
-----------
 welcome
0 голосов
/ 10 марта 2015

Это более общий ответ на вопрос «как получить последний элемент массива».

trader=# create table temp (name varchar);
CREATE TABLE

trader=# insert into temp (name) values ('foo bar baz');
INSERT 0 1

trader=# select (regexp_split_to_array(name, ' ')) from temp;
 regexp_split_to_array 
-----------------------
 {foo,bar,baz}
(1 row)

trader=# select (regexp_split_to_array(name, ' '))[array_upper(regexp_split_to_array(name, ' '), 1)] from temp;
 regexp_split_to_array 
-----------------------
 baz
(1 row)

array_upper

Возвращает индекс последнего элемента массива. Таким образом, чтобы использовать его, вы должны ссылаться на массив дважды: some_array[array_upper(some_array, 1)]


Итак, если у вас уже есть свой массив:

trader=# create view temp2 as  (select regexp_split_to_array(name, ' ') as name_parts from temp);
CREATE VIEW

trader=# select * from temp2;
  name_parts   
---------------
 {foo,bar,baz}
(1 row)

Менее многословно выбрать последний элемент:

trader=# select name_parts[array_upper(name_parts, 1)] from temp2;
 name_parts 
------------
 baz
(1 row)
0 голосов
/ 04 февраля 2014

Вы можете объединить string_to_array и array_length

select 
(string_to_array(column_name, '.'))[array_length((string_to_array(column_name, '.')), 1)]
from table_name;

Это разделит строку в column_name на массив, используя "." как разделитель и даст вам последнюю часть

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...