Jak połączyć kolumny w Postgres SELECT?

145

Mam dwie kolumny ciągów ai bw tabeli foo.

select a, b from foozwraca wartości ai b. Jednak konkatenacja ai bnie działa. Próbowałem :

select a || b from foo

i

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

Aktualizacja z komentarzy: obie kolumny są typu character(2).

Alex
źródło
... czy inny texttyp?
PM 77-1
@acfrancis Ponieważ OP mówi, concatenateże wątpię, czy ma do czynienia z typami numerycznymi, chociaż PostgreSQL zająłby się również niektórymi z nich. Zobacz tutaj: postgresql.org/docs/9.1/static/functions-string.html
PM 77-1
Tak, te kolumny są znakami (2). „+” nie działa - „Żaden operator nie pasuje do podanej nazwy i typów argumentów. Może być konieczne dodanie jawnych rzutów typu”.
Alex
Jaka wersja PostgreSQL? Oto dokumentacja do wersji 9.1: postgresql.org/docs/9.1/static/functions-string.html . Zobacz mój przykład: sqlfiddle.com/#!15/d41d8/182
PM 77-1
Prawdopodobnie w zapytaniu występuje błąd składni niezwiązany z konkatenacją.
PM 77-1

Odpowiedzi:

260

W przypadku kolumn typu łańcuchowego, takich jak character(2)(jak wspomniałeś później), wyświetlona konkatenacja działa tylko dlatego, że cytując instrukcję:

[...] operator konkatenacji łańcuchów ( ||) akceptuje dane wejściowe niebędące łańcuchami, o ile przynajmniej jedno wejście jest typu łańcuchowego , jak pokazano w tabeli 9.8 . W innych przypadkach wstaw wyraźny przymus text[...]

Odważne podkreślenie moje. Drugi przykład ( select a||', '||b from foo) działa dla wszystkich typów danych, ponieważ nietypowy literał ciągu ', 'domyślnie textprzyjmuje typ, dzięki czemu całe wyrażenie jest poprawne w każdym przypadku.

W przypadku typów danych innych niż łańcuchowe można „naprawić” pierwszą instrukcję, rzutując co najmniej jeden argument na text. ( Można rzutować dowolny typ text):

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

Sądząc po twojej własnej odpowiedzi , „ nie działa ” miało oznaczać „ zwraca NULL ”. Wynikiem wszystkiego połączonego z wartością NULL jest NULL. Jeśli w grę mogą wchodzić wartości NULL, a wynik nie będzie NULL, użyj concat_ws()do konkatenacji dowolnej liczby wartości (Postgres 9.1 lub nowszy):

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

Lub concat()jeśli nie potrzebujesz separatorów:

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

Nie ma tu potrzeby rzutowania typów, ponieważ obie funkcje pobierają "any"dane wejściowe i pracują z reprezentacjami tekstu.

Więcej szczegółów (i dlaczego COALESCEjest kiepskim substytutem) w tej powiązanej odpowiedzi:

Odnośnie aktualizacji w komentarzu

+nie jest prawidłowym operatorem konkatenacji ciągów znaków w Postgres (lub standardowym SQL). Dodanie tego do swoich produktów jest prywatnym pomysłem firmy Microsoft.

Nie ma żadnego powodu, aby używać character(n)(synonim:) char(n). Użyj textlubvarchar . Detale:

Erwin Brandstetter
źródło
Dziękuję Ci. Pierwsza wersja nie działa z wartością null, a druga dała mi błąd dotyczący concat_ws: Żadna funkcja nie pasuje do podanej nazwy i typów argumentów. Może być konieczne dodanie wyraźnych rzutów typu.
Alex
1
Widziałeś Postgres 9.1 or later, prawda? Na początek w pytaniu powinieneś podać swoją wersję Postgres . Proszę zaktualizować swoje pytanie ze wszystkich żądanych informacji, zanim wróci do niczego innego.
Erwin Brandstetter
Dziękuję, rozwiązanie, które znalazłem, działa dla każdej wersji Postgres
Alex
SELECT concat(a, b) FROM foo;działa dla mnie w Postgres 9.3, kiedy ai bVARCHAR.
elimisteve
Dziękuję za odpowiedź, rozwiązała mój problem :).
Ashwaqar
33

Problem polegał na zerach w wartościach; wtedy konkatenacja nie działa z wartościami null. Rozwiązanie jest następujące:

SELECT coalesce(a, '') || coalesce(b, '') FROM foo;
Alex
źródło
18

do konkatenacji lepiej jest użyć funkcji CONCAT w PostgreSQL

np .: select CONCAT(first_name,last_name) from person where pid = 136

jeśli używasz column_a || '' || kolumna_b do konkatenacji dla 2 kolumn, jeśli którakolwiek z wartości w kolumnie_a lub kolumna_b ma wartość null, zapytanie zwróci wartość null. co może nie być preferowane we wszystkich przypadkach ... więc zamiast tego

||

posługiwać się

CONCAT

zwróci odpowiednią wartość, jeśli którykolwiek z nich ma wartość

arjun nagathankandy
źródło
7

Funkcje CONCAT czasami nie działają ze starszą wersją PostgreSQL

zobacz, czego użyłem do rozwiązania problemu bez użycia CONCAT

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

Lub też możesz użyć

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

w drugim przypadku użyłem podwójnych cudzysłowów dla imienia i nazwiska

Mam nadzieję, że to się przyda, dzięki

Rameshwar Vyevhare
źródło
1
jeśli moje imię lub nazwisko ma wartość null,
połącz
2

Ponieważ też utknąłem w tym, myślę, że powinienem podzielić się rozwiązaniem, które najlepiej mi pasuje. Myślę też, że jest to znacznie prostsze.

Jeśli używasz nazwy tabeli pisanej wielkimi literami.

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

Jeśli używasz nazwy tabeli małymi literami

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

Otóż ​​to!. Ponieważ PGSQL liczy podwójne cudzysłowy dla deklaracji kolumn i pojedyncze cudzysłowy dla ciągu znaków, działa to jak urok.

Rakib Uddin
źródło
1

Framework PHP Laravel, używam wyszukiwania first_name, last_name Pola traktują jak Full Name Search

Korzystanie || symbol Lub metody 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);

Ten zadziałał urok !!!

venkatskpi
źródło
0

Spróbuj tego

select textcat(textcat(FirstName,' '),LastName) AS Name from person;
Muhammad Sadiq
źródło
8
concat_ws(' ', FirstName, LastName)byłoby znacznie czystsze.
a_horse_with_no_name
-1

Na przykład, jeśli istnieje tabela pracowników, która składa się z kolumn takich jak:

employee_number,f_name,l_name,email_id,phone_number 

jeśli chcemy połączyć f_name + l_namejako name.

SELECT employee_number,f_name ::TEXT ||','|| l_name::TEXT  AS "NAME",email_id,phone_number,designation FROM EMPLOYEE;
Abhishek Mitra
źródło
Co ta odpowiedź dodaje do istniejących odpowiedzi?
Erwin Brandstetter