Bedingte Zeichenfolgenverkettung in PostgreSQL

7

Ich habe eine Tabelle , parcelsdie zur Zeit die Spalten enthält owner_addr1, owner_addr2, owner_addr3. Manchmal ist eines oder beide der beiden letztgenannten Felder leer. Ich möchte sie in einem einzigen neuen Feld kombinieren, in owner_addrdem jedes der oben genannten Felder mit //jedem von ihnen verknüpft ist .

Wenn jedoch eine oder mehrere der ursprünglichen Spalten NULL sind, möchte ich nicht //mit der Ergebnisspalte verketten . So zum Beispiel, wenn owner_addr1ist 123 4th Avenue SEund owner_addr2und owner_addr3sind NULL, dann möchte ich die Ergebnisspalte nur sein 123 4th Avenue SE, nicht 123 4th Avenue SE // //(was passieren würde , wenn ich gerade tat CONCAT()mit //zwischen den NULL - Strings ... ich nur hinzufügen möchten //zwischen nicht NULLSpalten oder es verlassen insgesamt aus, wenn es nur eine Nicht- NULLSpalte gibt.

Gibt es eine einfache Möglichkeit, diese Art der bedingten Verkettung in Postgresql durchzuführen, bei der leere Zeilen weggelassen werden? Oder sollte ich dazu ein Python-Skript schreiben?

J. Taylor
quelle
1
Verwandte Antwort, die hilfreich sein kann: stackoverflow.com/q/12310986/939860 . Beachten Sie den letzten Teil über concat_ws()(und concat()) Funktionsvolatilität STABLE(nicht IMMUTABLE), der deren direkte Verwendung in Ausdrucksindizes verbietet.
Erwin Brandstetter

Antworten:

13

Die Funktion concat_ws()macht genau das, was Sie wollen. Der erste Parameter wird als Klebstoff zwischen den übrigen verwendet. Nullen werden ignoriert:

select concat_ws('//', owner_addr1, owner_addr2, owner_addr3)

Prüfung:

red=# select concat_ws('//', 'abc', null, null, 'xx', null, 'xyz', null) 
          as address;
   address    
--------------
 abc//xx//xyz
(1 row)
ypercubeᵀᴹ
quelle
2

Am offensichtlichsten ist es wahrscheinlich, eine CASE-Anweisung zu verwenden. Es gibt 4 Fälle:

owner_addr2 IS NULL AND owner_addr3 IS NULL => ''       
owner_addr2 IS NULL AND owner_addr3 IS NOT NULL => '//' || owner_addr3
owner_addr2 IS NOT NULL AND owner_addr3 IS NULL => '//' || owner_addr2
owner_addr2 IS NOT NULL AND owner_addr3 IS NOT NULL '//' || owner_addr2 || '//' owner_addr3

SELECT owner_addr1 
    || CASE WHEN owner_addr2 IS NULL AND owner_addr3 IS NULL
            THEN ''
            WHEN owner_addr2 IS NULL AND owner_addr3 IS NOT NULL
            THEN '//' || owner_addr3
            WHEN owner_addr2 IS NOT NULL AND owner_addr3 IS NULL 
            THEN '//' || owner_addr2   
            WHEN owner_addr2 IS NOT NULL AND owner_addr3 IS NOT NULL 
            THEN '//' || owner_addr2 || '//' || owner_addr3
       END AS owner_addr
FROM ...

Eine Alternative besteht darin, 2 CASE-Anweisungen zu verwenden:

SELECT owner_addr1 
    || CASE WHEN owner_addr2 IS NULL 
            THEN '' 
            ELSE '//' || owner_addr2
       END
    || CASE WHEN owner_addr3 IS NULL 
            THEN '' 
            ELSE '//' || owner_addr3
       END as owner_addr
FROM ...

COALESCE kann anstelle von CASE verwendet werden:

SELECT owner_addr1 
    || COALESCE('//' || owner_addr2, '')
    || COALESCE('//' || owner_addr3, '') as owner_addr
FROM ...
Lennart
quelle
Beachten Sie, dass die Antwort davon ausgeht, dass dies owner_addr1nicht null ist (die Frage scheint dies zu implizieren, daher sollte es in Ordnung sein).
Ypercubeᵀᴹ
1
Ja, das habe ich angenommen. Wird komplizierter, wenn dies nicht der Fall ist. CONCAT_WS sieht aus wie eine nette Funktion, erinnert mich an LISP :-)
Lennart
1
Die Koaleszenzform kann verwendet werden, die drei Begriffe gleich und dann ein Teilstring-Hacken des Starts
Jasen