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 internobpchar
).
Leitura adicional:
- Como verificar se existe uma tabela em um determinado esquema
- Truncando a exibição por padrão em instruções postgres psql select
- PostgreSQL força maiúsculas para todos os dados
- Verifique se as strings vazias estão presentes nas colunas do tipo caractere