Получение последнего слова из строки Postgres декларативно
[EDIT] оригинальным названием этого вопроса было "Получение последнего элемента массива Postgres, декларативно"
Как получить последний элемент массива в Postgres?
Мне нужно сделать это декларативно, поскольку я хочу использовать его как критерии ORDER BY. Я бы не хотел создавать для него специальную функцию PGSQL, тем меньше изменений в базе данных в этом случае лучше.
Фактически, я хочу, чтобы сортировать по последнему слову определенного столбца, содержащего несколько слов. Изменение модели здесь не является вариантом.
Другими словами, я хочу нажать Ruby sort_by {|x| x.split[-1]}
на уровень базы данных. Я могу разделить значение на массив слов с функциями Postgres string_to_array
или regexp_split_to_array
, а затем как получить его последний элемент?
Ответы
Ответ 1
Если я правильно понял ваш вопрос, у вас есть строка, и вы сначала разделите ее на каком-то разделителе, а затем наследуете последний элемент массива и отбрасываете остальные.
Вы можете пропустить среднего человека и получить последний элемент напрямую:
SELECT regexp_replace('foo bar baz', '^.* ', '')
Результат:
baz
Ответ 2
Используйте array_upper():
SELECT array_upper(ARRAY[1,2,5,6], 1);
Ответ 3
Q: я хочу, чтобы сортировать по последнему слову определенного столбца
При работе с фактическим массивом text
(а не строкой) используйте array_upper()
в индекс.
Демонстрация для 1-мерного массива
WITH x(a) AS (
VALUES
('{zoo, zar, zaz}'::text[])
,('{3,4,5,6}')
,('{foo, bar, baz}')
)
SELECT *
FROM x
ORDER BY a[array_upper(a, 1)];
Демонстрация для 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 a[array_upper(a, 1)][array_upper(a, 2)];
Ответ 4
UPDATE: вопрос был отредактирован, поэтому я обновляю свой ответ.
Вы также можете использовать array_upper() для возврата самого элемента (а не только его индекса):
SELECT arr[array_upper(arr, 1)] FROM (SELECT ARRAY[1,2,3,6] AS arr) AS t
Итак, anwer:
SELECT arr[array_upper(arr, 1)] FROM (SELECT string_to_array('one two three', ' ') AS arr) AS t
результат: 'three'
Ответ 5
Вы можете сделать следующее:
SELECT (ARRAY[1,8,3,7])[array_upper(ARRAY[1,8,3,7], 1)];
т.е. получить индекс, а затем выбрать последний элемент.
Ответ 6
Отредактировано: THIS WRONG - ВИДЕТЬ НИЖЕ ДЛЯ ПРАВИЛЬНОГО ОТВЕТА -
Думаю, вы должны использовать 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
------- EDITED - ПРАВИЛЬНЫЙ ОТВЕТ ПОСЛЕДУЕТ ----------------------
Вышеприведенное неверно, потому что в массивах 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
Ответ 7
Вы можете комбинировать string_to_array и array_length
select
(string_to_array(column_name, '.'))[array_length((string_to_array(column_name, '.')), 1)]
from table_name;
Это разделит строку в столбце_имя на массив, используя "." как разделитель и даст вам последнюю часть
Ответ 8
Это более общий ответ на вопрос "как получить последний элемент массива".
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)