sql >> Base de Datos >  >> RDS >> PostgreSQL

quote_ident () no agrega comillas al nombre de la columna primero

No omita AS palabra clave para alias de columna

No exactamente. Explota porque omitió la palabra clave AS donde no debe omitirse.

Esto funciona:

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";

Que funciona como se esperaba a su vez.

El manual sobre "Omitir el COMO palabra clave" :

Está bien omitir la palabra clave AS para alias de tabla, pero no para alias de columna.

first no es una palabra reservada en Postgres. (Solía ​​estar "reservado" en el antiguo SQL estándar SQL-92, pero ya no en SQL estándar). Es "no reservado" * para ser preciso. El manual :

Omitiendo AS lo convierte en tal contexto.

quote_ident() funciona de manera confiable. El manual:

format() con el especificador %I hace lo mismo.

Las palabras reservadas no se mencionan, pero se citan correctamente independientemente. Para ser precisos:todas las palabras clave marcadas "reservadas" o "(no puede ser función ni tipo)" en la columna "PostgreSQL" de la Palabras clave de SQL mesa .

Archivaré un error de documentación para agregar eso.

Para estar absolutamente seguro:quote_all_identifiers

Si quiere estar absolutamente seguro y no le importa todo el ruido agregado, puede obligar a Postgres a citar todo identificadores con el parámetro de configuración quote_all_identifiers . El manual:

Eso incluye la salida de quote_ident() y format() . Yo no haz eso, temiendo todo el ruido adicional.

Puede establecer el parámetro localmente con SET LOCAL en la misma transacción. Me gusta:

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

Más rápido

Dicho esto, usaría format() y concat() y apunte a la tabla de catálogo pg_attribute en cambio:más limpio, más simple, más rápido. Pero no portátil a otros 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<>fiddle aquí

En particular, ...

  • ... solo necesita proporcionar el nombre de la tabla una vez, opcionalmente calificado para el esquema.
  • ... si la tabla no existe, la consulta falla inmediatamente con un útil mensaje de error.
  • ... el nombre de la tabla de salida solo está calificado como esquema y entre comillas dobles donde sea necesario.
  • ... esto también cubre character(N) (nombre interno bpchar ).

Lectura adicional: