it-swarm.com.de

Kombiniere zwei Spalten und füge sie zu einer neuen hinzu

In PostgreSQL möchte ich eine SQL-Anweisung verwenden, um zwei Spalten zu kombinieren und daraus eine neue Spalte zu erstellen.

Ich denke über die Verwendung von concat(...) nach, aber gibt es einen besseren Weg?
Wie geht das am besten?

30
Rock

Im Allgemeinen stimme ich @ kgrittns Rat zu. Tue es.

Aber um Ihre grundlegende Frage zu beantworten: concat() : Die neue Funktion concat() ist nützlich, wenn Sie sich mit Nullwerten beschäftigen müssen und Null in Ihrer Frage und der Frage, auf die Sie sich beziehen, weder ausgeschlossen wurde.

Wenn Sie Nullwerte ausschließen können, bleibt der gute alte (SQL-Standard) Verkettungsoperator || bestehen die beste Wahl, und @ Luis 'Antwort ist in Ordnung:

SELECT col_a || col_b;

Wenn eine Ihrer Spalten null sein kann, ist das Ergebnis in diesem Fall null. Sie könnten mit COALESCE verteidigen:

SELECT COALESCE(col_a, '') || COALESCE(col_b, '');

Aber mit mehr Argumenten wird das schnell langweilig. Hier kommt concat() ins Spiel, was never null zurückgibt, auch wenn all Argumente null sind. Pro Dokumentation :

NULL-Argumente werden ignoriert.

SELECT concat(col_a, col_b);

Der verbleibende Eckfall für beide Alternativen besteht darin, dass alle Eingabespalten null sind In diesem Fall erhalten wir immer noch einen leeren String '', aber man möchte vielleicht stattdessen null (zumindest würde ich das tun). Ein möglicher Weg:

SELECT CASE
          WHEN col_a IS NULL THEN col_b
          WHEN col_b IS NULL THEN col_a
          ELSE col_a || col_b
       END

Dies wird mit schnelleren Spalten komplexer. Verwenden Sie erneut concat(), aber fügen Sie eine Prüfung für die spezielle Bedingung hinzu:

SELECT CASE WHEN (col_a, col_b) IS NULL THEN NULL
            ELSE concat(col_a, col_b) END;

Wie funktioniert das?
(col_a, col_b) Ist eine Kurzschreibweise für einen Zeilentyp-Ausdruck ROW (col_a, col_b). Und ein Zeilentyp ist nur null, wenn all Spalten null sind. Ausführliche Erklärung:

Verwenden Sie auch concat_ws() , um Trennzeichen zwischen Elementen einzufügen (_ws .. " mit Trennzeichen ").


Ein Ausdruck wie in Kevins Antwort:

SELECT $1.zipcode || ' - ' || $1.city || ', ' || $1.state;

es ist mühsam, sich in PostgreSQL 8.3 auf Nullwerte vorzubereiten (ohne concat()). Ein Weg (von vielen):

SELECT COALESCE(
         CASE
          WHEN $1.zipcode IS NULL THEN $1.city
          WHEN $1.city IS NULL THEN $1.zipcode
          ELSE $1.zipcode || ' - ' || $1.city
         END, '')
       || COALESCE(', ' || $1.state, '');

Die Funktionsvolatilität ist nur STABLE

Beachten Sie jedoch, dass concat() und concat_ws()STABLE Funktionen sind, nicht IMMUTABLE, da sie Datentyp-Ausgabefunktionen aufrufen können (wie timestamptz_out), die von den Ländereinstellungen abhängen. Erklärung von Tom Lane.

Dies verbietet ihre direkte Verwendung in Indexausdrücken. Wenn Sie know wissen, dass das Ergebnis in Ihrem Fall tatsächlich unveränderlich ist, können Sie dies mit einem IMMUTABLE -Funktionswrapper umgehen. Beispiel hier:

66

Sie müssen die Spalte nicht speichern, um auf diese Weise darauf zu verweisen. Versuche dies:

So richten Sie ein:

CREATE TABLE tbl
  (zipcode text NOT NULL, city text NOT NULL, state text NOT NULL);
INSERT INTO tbl VALUES ('10954', 'Nanuet', 'NY');

Wir können sehen, dass wir "das Richtige" haben:

\pset border 2
SELECT * FROM tbl;
 + --------- + -------- + ------- + 
 | Postleitzahl | Stadt | state | 
 + --------- + -------- + ------- + 
 | 10954 | Nanuet | NY | 
 + --------- + -------- + ------- + 

Fügen Sie nun eine Funktion mit dem gewünschten "Spaltennamen" hinzu, die den Datensatztyp der Tabelle als einzigen Parameter verwendet:

CREATE FUNCTION combined(rec tbl)
  RETURNS text
  LANGUAGE SQL
AS $$
  SELECT $1.zipcode || ' - ' || $1.city || ', ' || $1.state;
$$;

Dadurch wird eine Funktion erstellt, die wie eine Tabellenspalte verwendet werden kann, sofern der Tabellenname oder der Alias ​​wie folgt angegeben wird:

SELECT *, tbl.combined FROM tbl;

Welche Displays sehen so aus:

 + --------- + -------- + ------- + ----------------- --- + 
 | Postleitzahl | Stadt | Zustand | kombiniert | 
 + --------- + -------- + ------- + --------------- ----- + 
 | 10954 | Nanuet | NY | 10954 - Nanuet, NY | 
 + --------- + -------- + ------- + ----------- --------- + 

Dies funktioniert, weil PostgreSQL zuerst nach einer tatsächlichen Spalte sucht. Wenn jedoch keine Spalte gefunden wird und der Bezeichner mit einem Beziehungsnamen oder Alias ​​qualifiziert ist, sucht es nach einer Funktion wie der obigen und führt sie mit der Zeile als Argument aus und gibt sie zurück das Ergebnis, als ob es eine Spalte wäre. Sie können sogar eine solche "generierte Spalte" indizieren, wenn Sie dies möchten.

Da Sie nicht in jeder Zeile zusätzlichen Platz für die duplizierten Daten verwenden oder Auslöser für alle Einfügungen und Aktualisierungen auslösen, kann dies häufig schneller als die Alternativen sein.

15
kgrittn

Haben Sie die Funktion zur Verkettung von Zeichenfolgen überprüft? Etwas wie:

update table_c set column_a = column_b || column_c 

sollte arbeiten. Mehr hier

13
luis