Как объединить столбцы в Postgres SELECT?

145

У меня есть два строковых столбца aи bв таблице foo.

select a, b from fooвозвращает значения aи b. Однако конкатенация aи bне работает. Я попытался :

select a || b from foo

и

select  a||', '||b from foo

Обновление из комментариев: оба столбца являются типом character(2).

Alex
источник
... или другой textтип?
ПМ 77-1
@acfrancis Поскольку OP говорит, что concatenateя сомневаюсь, что он имеет дело с числовыми типами, хотя PostgreSQL позаботится и о некоторых из них. Смотрите здесь: postgresql.org/docs/9.1/static/functions-string.html
PM 77-1
Да, эти столбцы являются символом (2). «+» не работает - «Ни один оператор не соответствует заданному имени и типу (ам) аргумента. Возможно, вам придется добавить явное приведение типов».
Алекс
Какая версия PostgreSQL? Вот документы для 9.1: postgresql.org/docs/9.1/static/functions-string.html . Смотрите мой пример: sqlfiddle.com/#!15/d41d8/182
PM 77-1
Возможно, в вашем запросе есть синтаксическая ошибка, не связанная с конкатенацией.
PM 77-1

Ответы:

260

С такими столбцами строкового типа, как character(2)(как вы упоминали позже), отображаемая конкатенация работает, потому что, цитируя руководство:

[...] оператор конкатенации строк ( ||) принимает не строковые данные, если хотя бы один из них имеет строковый тип , как показано в таблице 9.8 . Для других случаев вставьте явное принуждение к text[...]

Жирный акцент мой. 2-й пример ( select a||', '||b from foo) работает для любых типов данных, так как нетипизированный строковый литерал по ', 'умолчанию набирает тип, textделая все выражение действительным в любом случае.

Для нестроковых типов данных вы можете «исправить» 1-й оператор, приведя хотя бы один аргумент к text. ( Любой тип может быть приведен к text):

SELECT a::text || b AS ab FROM foo;

Судя по вашему собственному ответу , « не работает » должно было означать « возвращает NULL ». Результатом всего, что связано с NULL, является NULL. Если могут использоваться значения NULL и результат не должен быть NULL, используйте concat_ws()для объединения любого числа значений (Postgres 9.1 или более поздняя версия):

SELECT concat_ws(', ', a, b) AS ab FROM foo;

Или, concat()если вам не нужны разделители:

SELECT concat(a, b) AS ab FROM foo;

Здесь нет необходимости в приведении типов, поскольку обе функции принимают "any"ввод и работают с текстовыми представлениями.

Более подробно (и почему COALESCEэто плохая замена) в этом связанном ответе:

По поводу обновления в комментарии

+не является допустимым оператором для конкатенации строк в Postgres (или стандартном SQL). Это частная идея Microsoft - добавить это в свои продукты.

Вряд ли есть веская причина для использования character(n)(синоним:) char(n). Используйте textилиvarchar . Подробности:

Эрвин Брандштеттер
источник
Спасибо. Первая версия не работает с нулем, а вторая дала мне ошибку для concat_ws: ни одна функция не соответствует заданному имени и типу аргумента. Возможно, вам придется добавить явное приведение типов.
Alex
1
Вы видели Postgres 9.1 or later, верно? Вы должны были предоставить свою версию Postgres для начала, в вопросе . Пожалуйста, обновите ваш вопрос со всей запрашиваемой информацией, прежде чем вернуться к чему-либо еще.
Эрвин Брандштеттер
Спасибо, решение, которое я нашел, работает для любой версии Postgres
Alex
SELECT concat(a, b) FROM foo;у меня работает в Postgres 9.3 когда aи bесть VARCHARс.
elimisteve
Спасибо за ваш ответ, это решило мою проблему :).
Ашвакар
34

Проблема была в нулях в значениях; тогда конкатенация не работает с нулями. Решение заключается в следующем:

SELECT coalesce(a, '') || coalesce(b, '') FROM foo;
Alex
источник
18

для конкатенации лучше использовать функцию CONCAT в PostgreSQL

например: select CONCAT(first_name,last_name) from person where pid = 136

если вы используете column_a || '' || column_b для конкатенации для 2-х столбцов, если любое из значений в column_a или column_b равно нулю, запрос вернет нулевое значение. что не может быть предпочтительным во всех случаях .. поэтому вместо этого

||

использование

CONCAT

он вернет соответствующее значение, если любой из них имеет значение

Арджун Нагатанканды
источник
7

Функции CONCAT иногда не работают со старой версией postgreSQL

посмотрите, что я использовал для решения проблемы без использования CONCAT

 u.first_name || ' ' || u.last_name as user,

Или также вы можете использовать

 "first_name" || ' ' || "last_name" as user,

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

Надеюсь, это будет полезно, спасибо

Рамешвар Веххаре
источник
1
если мое имя или фамилия
пустые,
2

Поскольку я также застрял в этом, думаю, что я должен поделиться решением, которое работало лучше всего для меня. Я также думаю, что это намного проще.

Если вы используете имя заглавной таблицы.

SELECT CONCAT("firstName", ' ', "lastName") FROM "User"

Если вы используете имя таблицы в нижнем регистре

SELECT CONCAT(firstName, ' ', lastName) FROM user

Это оно!. Поскольку PGSQL считает двойную кавычку для объявления столбца и одинарную кавычку для строки, это работает как шарм.

Ракиб Уддин
источник
1

PHP каркас Laravel, я использую поиск first_name, last_name Поля считают похожими на поиск полного имени

Использование || символ или методы concat_ws (), concat ()

$names = str_replace(" ", "", $searchKey);                               
$customers = Customer::where('organization_id',$this->user->organization_id)
             ->where(function ($q) use ($searchKey, $names) {
                 $q->orWhere('phone_number', 'ilike', "%{$searchKey}%"); 
                 $q->orWhere('email', 'ilike', "%{$searchKey}%");
                 $q->orWhereRaw('(first_name || last_name) LIKE ? ', '%' . $names. '%');
    })->orderBy('created_at','desc')->paginate(20);

Это сработало очарование !!!

venkatskpi
источник
0

Попробуй это

select textcat(textcat(FirstName,' '),LastName) AS Name from person;
Мухаммед Садик
источник
8
concat_ws(' ', FirstName, LastName)будет намного чище.
a_horse_with_no_name
-1

Например, если есть таблица сотрудников, которая состоит из столбцов в виде:

employee_number,f_name,l_name,email_id,phone_number 

если мы хотим объединить f_name + l_nameкак name.

SELECT employee_number,f_name ::TEXT ||','|| l_name::TEXT  AS "NAME",email_id,phone_number,designation FROM EMPLOYEE;
Абхишек Митра
источник
Что этот ответ добавляет к существующим ответам?
Эрвин Брандштеттер