it-swarm.com.de

Wie füge ich eine Spalte hinzu, wenn sie nicht in PostgreSQL existiert?

Die Frage ist einfach. Wie füge ich die Spalte x zur Tabelle y hinzu, aber nur, wenn die Spalte x nicht existiert? Ich fand nur Lösung hier wie man prüft, ob Spalte existiert.

SELECT column_name 
FROM information_schema.columns 
WHERE table_name='x' and column_name='y';
118
marioosh

Hier ist eine Kurzfassung mit der Anweisung "DO":

DO $$ 
    BEGIN
        BEGIN
            ALTER TABLE <table_name> ADD COLUMN <column_name> <column_type>;
        EXCEPTION
            WHEN duplicate_column THEN RAISE NOTICE 'column <column_name> already exists in <table_name>.';
        END;
    END;
$$

Sie können diese nicht als Parameter übergeben. Sie müssen die Zeichenfolge auf der Clientseite durch Variablen ersetzen. Dies ist jedoch eine eigenständige Abfrage, die nur dann eine Nachricht ausgibt, wenn die Spalte bereits vorhanden ist schlägt bei anderen Fehlern (wie einem ungültigen Datentyp) weiterhin fehl.

Ich empfehle, KEINE dieser Methoden anzuwenden, wenn es sich um zufällige Zeichenfolgen handelt, die aus externen Quellen stammen. Unabhängig davon, welche Methode Sie verwenden (cleint-seitige oder serverseitige dynamische Zeichenfolgen, die als Abfragen ausgeführt werden), ist dies ein Rezept für eine Katastrophe, da Sie für SQL-Injection-Angriffe offen sind.

118
Matthew Wood

Mit Postgres 9.6 kann dies mit der Option if not exists

ALTER TABLE table_name ADD COLUMN IF NOT EXISTS column_name INTEGER;
262
CREATE OR REPLACE function f_add_col(_tbl regclass, _col  text, _type regtype)
  RETURNS bool AS
$func$
BEGIN
   IF EXISTS (SELECT 1 FROM pg_attribute
              WHERE  attrelid = _tbl
              AND    attname = _col
              AND    NOT attisdropped) THEN
      RETURN FALSE;
   ELSE
      EXECUTE format('ALTER TABLE %s ADD COLUMN %I %s', _tbl, _col, _type);
      RETURN TRUE;
   END IF;
END
$func$  LANGUAGE plpgsql;

Anruf:

SELECT f_add_col('public.kat', 'pfad1', 'int');

Gibt bei Erfolg TRUE zurück, sonst FALSE (Spalte existiert bereits).
Löst eine Ausnahme für ungültigen Tabellen- oder Typnamen aus.

Warum eine andere Version?

  • Dies könnte mit einer DO -Anweisung geschehen, aber DO -Anweisungen können nichts zurückgeben. Und wenn es für den wiederholten Gebrauch ist, würde ich eine Funktion erstellen.

  • Ich benutze die Objektidentifikationstypenregclass und regtype für _tbl Und _type, Die a) die SQL-Injection verhindern und b) prüfen Gültigkeit von beiden sofort (billigster Weg möglich). Der Spaltenname _col Muss noch für EXECUTE mit quote_ident() bereinigt werden. Weitere Erklärung in dieser verwandten Antwort:

  • format() benötigt Postgres 9.1+. Für ältere Versionen verketten Sie manuell:

    EXECUTE 'ALTER TABLE ' || _tbl || ' ADD COLUMN ' || quote_ident(_col) || ' ' || _type;
    
  • Sie können Ihren Tabellennamen anhand eines Schemas qualifizieren, müssen dies aber nicht.
    Sie können die Bezeichner im Funktionsaufruf in doppelte Anführungszeichen setzen, um die Groß- und Kleinschreibung und reservierte Wörter beizubehalten (aber Sie sollten sowieso nichts davon verwenden).

  • Ich frage pg_catalog Anstelle von information_schema Ab. Ausführliche Erklärung:

  • Blöcke, die eine EXCEPTION -Klausel wie die aktuell akzeptierte Antwort enthalten, sind wesentlich langsamer. Dies ist in der Regel einfacher und schneller. Die Dokumentation:

Tipp: Ein Block mit einer EXCEPTION -Klausel ist beim Ein- und Ausstieg erheblich teurer als ein Block ohne eine. Verwenden Sie daher EXCEPTION nicht ohne Notwendigkeit.

21

Die folgende Auswahlabfrage gibt true/false Mit der Funktion EXISTS() zurück.

EXISTS () :
Das Argument von EXISTS ist eine beliebige SELECT-Anweisung oder Unterabfrage. Die Unterabfrage wird ausgewertet, um festzustellen, ob Zeilen zurückgegeben werden. Wenn mindestens eine Zeile zurückgegeben wird, ist das Ergebnis von EXISTS "true". Wenn die Unterabfrage keine Zeilen zurückgibt, ist das Ergebnis von EXISTS "false".

SELECT EXISTS(
SELECT column_name 
FROM information_schema.columns 
WHERE table_schema='public' 
  and table_name='x' 
  and column_name='y')

verwenden Sie die folgende dynamische SQL-Anweisung, um Ihre Tabelle zu ändern

DO
$$
BEGIN
IF not EXISTS (SELECT column_name 
               FROM information_schema.columns 
               WHERE table_schema='public' and table_name='x' and column_name='y') THEN
alter table x add column y int default null ;
else
raise NOTICE 'Already exists';
END IF;
END
$$
17
Vivek S.

die folgende Funktion überprüft die Spalte, falls vorhanden, und gibt die entsprechende Meldung zurück. Anderenfalls wird die Spalte der Tabelle hinzugefügt.

create or replace function addcol(schemaname varchar, tablename varchar, colname varchar, coltype varchar)
returns varchar 
language 'plpgsql'
as 
$$
declare 
    col_name varchar ;
begin 
      execute 'select column_name from information_schema.columns  where  table_schema = ' ||
      quote_literal(schemaname)||' and table_name='|| quote_literal(tablename) || '   and    column_name= '|| quote_literal(colname)    
      into   col_name ;   

      raise info  ' the val : % ', col_name;
      if(col_name is null ) then 
          col_name := colname;
          execute 'alter table ' ||schemaname|| '.'|| tablename || ' add column '|| colname || '  ' || coltype; 
      else
           col_name := colname ||' Already exist';
      end if;
return col_name;
end;
$$
1
solaimuruganv

Dies ist im Grunde die Lösung von Sola, aber nur ein bisschen aufgeräumt. Es ist anders genug, dass ich seine Lösung nicht nur "verbessern" wollte (außerdem finde ich das irgendwie unhöflich).

Der Hauptunterschied besteht darin, dass das EXECUTE-Format verwendet wird. Was ich für ein bisschen sauberer halte, aber meiner Meinung nach bedeutet, dass Sie auf PostgresSQL 9.1 oder neuer sein müssen.

Dies wurde auf 9.1 getestet und funktioniert. Hinweis: Es wird ein Fehler ausgegeben, wenn das Schema/tabellenname/oder der Datentyp ungültig sind. Das könnte "behoben" sein, aber in vielen Fällen auch das richtige Verhalten.

CREATE OR REPLACE FUNCTION add_column(schema_name TEXT, table_name TEXT, 
column_name TEXT, data_type TEXT)
RETURNS BOOLEAN
AS
$BODY$
DECLARE
  _tmp text;
BEGIN

  EXECUTE format('SELECT COLUMN_NAME FROM information_schema.columns WHERE 
    table_schema=%L
    AND table_name=%L
    AND column_name=%L', schema_name, table_name, column_name)
  INTO _tmp;

  IF _tmp IS NOT NULL THEN
    RAISE NOTICE 'Column % already exists in %.%', column_name, schema_name, table_name;
    RETURN FALSE;
  END IF;

  EXECUTE format('ALTER TABLE %I.%I ADD COLUMN %I %s;', schema_name, table_name, column_name, data_type);

  RAISE NOTICE 'Column % added to %.%', column_name, schema_name, table_name;

  RETURN TRUE;
END;
$BODY$
LANGUAGE 'plpgsql';

verwendung:

select add_column('public', 'foo', 'bar', 'varchar(30)');
1
David S

Sie können es auf folgende Weise tun.

ALTER TABLE tableName drop column if exists columnName; 
ALTER TABLE tableName ADD COLUMN columnName character varying(8);

So wird die Spalte gelöscht, wenn sie bereits vorhanden ist. Fügen Sie dann die Spalte zu einer bestimmten Tabelle hinzu.

0
parthivrshah

Kann zu Migrationsskripten hinzugefügt werden, um die Funktion aufzurufen und zu löschen, wenn dies abgeschlossen ist.

create or replace function patch_column() returns void as
$$
begin
    if exists (
        select * from information_schema.columns
            where table_name='my_table'
            and column_name='missing_col'
     )
    then
        raise notice 'missing_col already exists';
    else
        alter table my_table
            add column missing_col varchar;
    end if;
end;
$$ language plpgsql;

select patch_column();

drop function if exists patch_column();
0
user645527

In meinem Fall ist es für unsere Migrationsskripte aus den Gründen, aus denen sie erstellt wurden, etwas schwierig, verschiedene Schemata zu durchschneiden.

Um dies zu umgehen, haben wir eine Ausnahme verwendet, die den Fehler gerade abgefangen und ignoriert hat. Dies hatte auch den netten Nebeneffekt, dass es viel einfacher zu betrachten war.

Seien Sie jedoch vorsichtig, dass die anderen Lösungen ihre eigenen Vorteile haben, die diese Lösung wahrscheinlich überwiegen:

DO $$
BEGIN
  BEGIN
    ALTER TABLE IF EXISTS bobby_tables RENAME COLUMN "dckx" TO "xkcd";
  EXCEPTION
    WHEN undefined_column THEN RAISE NOTICE 'Column was already renamed';
  END;
END $$;
0
ThinkBonobo