PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

quote_ident() fügt dem Spaltennamen zuerst keine Anführungszeichen hinzu

Lassen Sie AS nicht aus Schlüsselwort für Spaltenaliase

Nicht genau. Es explodiert, weil Sie das Schlüsselwort AS weggelassen haben wo es nicht weggelassen werden sollte.

Das funktioniert:

SELECT 'select ' 
|| string_agg(
        case when udt_name in ('varchar', 'text')
            then 'left(' || quote_ident(column_name) || ', 65535) AS '  -- !!
              ||  quote_ident(column_name)
        else quote_ident(column_name)
        end, ', ' order by ordinal_position) 
|| ' from "public"."MyTableName"'
FROM information_schema.columns c
join parse_ident('"public"."MyTableName"') t 
on t[1] = table_schema and t[2] = table_name;

Erzeugt:

SELECT id, left(first, 65535) AS first from "public"."MyTableName";

Was wiederum wie erwartet funktioniert.

Das Handbuch zum "Weglassen der AS Schlüsselwort" :

Das Schlüsselwort AS kann weggelassen werden für Tabellenaliase, aber nicht für Spaltenaliase.

first ist kein reserviertes Wort in Postgres. (Früher war es im alten SQL-Standard SQL-92 "reserviert", aber auch nicht mehr im Standard-SQL.) Es ist "nicht reserviert" * um genau zu sein. Das Handbuch :

Weglassen von AS macht es zu einem solchen Kontext.

quote_ident() funktioniert zuverlässig. Das Handbuch:

format() mit dem Spezifizierer %I macht dasselbe.

Reservierte Wörter werden nicht erwähnt, aber trotzdem korrekt zitiert. Genauer gesagt:alle Schlüsselwörter, die mit "reserviert" gekennzeichnet sind oder "(kann weder Funktion noch Typ sein)" in der Spalte "PostgreSQL" von dem SQL-Schlüsselwörter Tabelle .

Ich werde einen Dokumentationsfehler einreichen, um das hinzuzufügen.

Um absolut sicher zu sein:quote_all_identifiers

Wenn Sie absolut sicher sein wollen und sich nicht um all das zusätzliche Rauschen kümmern, können Sie Postgres zwingen, alle zu zitieren Identifikatoren mit dem Konfigurationsparameter quote_all_identifiers . Das Handbuch:

Dazu gehört die Ausgabe von quote_ident() und format() . Ich würde nicht Tun Sie das und fürchten Sie all den zusätzlichen Lärm.

Sie können den Parameter lokal mit SET LOCAL setzen in derselben Transaktion. Wie:

BEGIN;
SET LOCAL quote_all_identifiers = true;
SELECT ...
END;

Schneller

Das heißt, ich würde format() verwenden und concat() und zielen Sie auf die Katalogtabelle pg_attribute stattdessen:sauberer, einfacher, schneller. Aber nicht auf andere RDBMS portierbar:

SELECT format('SELECT %s FROM %s;'
            , string_agg(CASE WHEN atttypid = ANY ('{text, bpchar, varchar}'::regtype[])
                              THEN concat('left(', col, ', 65535) AS ', col)
                              ELSE col END, ', ')
            , attrelid)
FROM  (
   SELECT attrelid::regclass, atttypid, quote_ident(attname) AS col
   FROM   pg_catalog.pg_attribute
   WHERE  attrelid = 'public."MyTableName"'::regclass  -- provide once, optionally schema-qualified
   AND    attnum > 0
   AND    NOT attisdropped
   ORDER  BY attnum
   ) sub
GROUP  BY attrelid;

Erzeugt:

SELECT id, left(first, 65535) AS first FROM "MyTableName";

db<>fiddle hier

Insbesondere ...

  • ... Sie müssen den Tabellennamen nur einmal angeben, optional schemaqualifiziert.
  • ... falls die Tabelle nicht existiert, schlägt die Abfrage sofort mit einer hilfreichen Fehlermeldung fehl.
  • ... der Name der Ausgabetabelle wird nur schemaqualifiziert und wo nötig in doppelte Anführungszeichen gesetzt.
  • ... dies gilt auch für character(N) (interner Name bpchar ).

Weiterführende Literatur: