PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

quote_ident() não adiciona aspas ao nome da coluna primeiro

Não omita AS palavra-chave para aliases de coluna


Não exatamente. Ele explode porque você omitiu a palavra-chave AS onde não deve ser omitido.

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

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

Que funciona como esperado por sua vez.

O manual sobre "Omitir o AS Palavra-chave" :

Não há problema em omitir a palavra-chave AS para aliases de tabela, mas não para aliases de coluna.

first não é uma palavra reservada em Postgres. (Ele costumava ser "reservado" no antigo padrão SQL SQL-92, mas não mais no SQL padrão.) É "não reservado" * para ser mais preciso. O manual :

Omitindo AS torna apenas tal contexto.

quote_ident() funciona de forma confiável. O manual:

format() com o especificador %I faz o mesmo.

As palavras reservadas não são mencionadas, mas citadas corretamente independentemente. Para ser preciso:todas as palavras-chave marcadas como "reservadas" ou "(não pode ser função ou tipo)" na coluna "PostgreSQL" do o Palavras-chave SQL mesa .

Vou registrar um bug de documentação para adicionar isso.

Para ter certeza absoluta:quote_all_identifiers


Se você quiser ter certeza absoluta e não se importar com todo o ruído adicionado, você pode forçar o Postgres a citar todos identificadores com o parâmetro de configuração quote_all_identifiers . O manual:

Isso inclui a saída de quote_ident() e format() . Eu não faça isso, temendo todo o barulho adicionado.

Você pode definir o parâmetro localmente com SET LOCAL na mesma transação. Curti:
BEGIN;
SET LOCAL quote_all_identifiers = true;
SELECT ...
END;

Mais rápido


Dito isso, eu usaria format() e concat() e direcione a tabela de catálogo pg_attribute em vez disso:mais limpo, mais simples, mais rápido. Mas não é portátil para outros 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;

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

db<>fiddle aqui

Notavelmente, ...
  • ... você só precisa fornecer o nome da tabela uma vez, opcionalmente qualificado pelo esquema.
  • ... se a tabela não existir, a consulta falhará imediatamente com uma mensagem de erro útil.
  • ... o nome da tabela de saída só é qualificado pelo esquema e aspas duplas quando necessário.
  • ... isso também abrange character(N) (nome interno bpchar ).

Leitura adicional: