PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

quote_ident() non aggiunge prima le virgolette al nome della colonna

Non omettere AS parola chiave per gli alias di colonna

Non esattamente. Esplode perché hai omesso la parola chiave AS dove non deve essere omesso.

Funziona:

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;

Produce:

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

Che a sua volta funziona come previsto.

Il manuale su "Omissione del AS Parola chiave" :

È possibile omettere la parola chiave AS per gli alias di tabella, ma non per gli alias di colonna.

first non è una parola riservata a Postgres. (Un tempo era "riservato" nell'antico standard SQL SQL-92, ma non più nemmeno nell'SQL standard.) È "non riservato" * per essere precisi. Il manuale :

Omettendo AS lo rende proprio un tale contesto.

quote_ident() funziona in modo affidabile. Il manuale:

format() con lo specificatore %I fa lo stesso.

Le parole riservate non sono menzionate, ma citate correttamente a prescindere. Per la precisione:tutte le parole chiave contrassegnate da "riservato" o "(non può essere funzione o tipo)" nella colonna "PostgreSQL" di il Parole chiave SQL tabella .

Rileverò un bug della documentazione per aggiungerlo.

Per essere assolutamente sicuri:quote_all_identifiers

Se vuoi essere assolutamente sicuro e non preoccuparti di tutto il rumore aggiunto, puoi forzare Postgres a citare tutto identificatori con il parametro di configurazione quote_all_identifiers . Il manuale:

Ciò include l'output di quote_ident() e format() . Io non fallo, temendo tutto il rumore aggiunto.

Puoi impostare il parametro localmente con SET LOCAL nella stessa transazione. Come:

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

Più veloce

Detto questo, userei format() e concat() e scegli come target la tabella del catalogo pg_attribute invece:più pulito, più semplice, più veloce. Ma non portabile su altri RDBMS:

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;

Produce:

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

db<>violino qui

In particolare, ...

  • ... devi fornire il nome della tabella solo una volta, facoltativamente qualificato per lo schema.
  • ... se la tabella non esiste, la query fallisce immediatamente con un utile messaggio di errore.
  • ... il nome della tabella di output è qualificato dallo schema e tra virgolette se necessario.
  • ... questo copre anche character(N) (nome interno bpchar ).

Ulteriori letture: