sql >> Database >  >> RDS >> PostgreSQL

quote_ident() voegt eerst geen aanhalingstekens toe aan de kolomnaam

Sla AS niet weg sleutelwoord voor kolomaliassen

Niet precies. Het ontploft omdat je het zoekwoord AS . hebt weggelaten waar het niet mag worden weggelaten.

Dit werkt:

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;

Produceert:

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

Wat op zijn beurt weer werkt zoals verwacht.

De handleiding over "Het weglaten van de ALS Sleutelwoord" :

Het is oké om het trefwoord AS weg te laten voor tabelaliassen, maar niet voor kolomaliassen.

first is geen gereserveerd woord in Postgres. (Het was "gereserveerd" in de oude SQL-standaard SQL-92, maar ook niet meer in standaard SQL.) Het is "niet-gereserveerd" * precies zijn. De handleiding :

Weglaten van AS maakt het zo'n context.

quote_ident() werkt betrouwbaar. De handleiding:

format() met de specificatie %I doet hetzelfde.

Gereserveerde woorden worden niet genoemd, maar toch correct geciteerd. Om precies te zijn:alle trefwoorden gemarkeerd met "gereserveerd" of "(kan geen functie of type zijn)" in de kolom "PostgreSQL" van de SQL-sleutelwoorden tafel .

Ik zal een documentatiebug indienen om dat toe te voegen.

Om absoluut zeker te zijn:quote_all_identifiers

Als je absoluut zeker wilt zijn en alle toegevoegde ruis niet erg vindt, kun je Postgres dwingen om alles te citeren identifiers met de configuratieparameter quote_all_identifiers . De handleiding:

Dat omvat uitvoer van quote_ident() en format() . Ik zou niet doe dat, bang voor al het extra lawaai.

U kunt de parameter lokaal instellen met SET LOCAL in dezelfde transactie. Vind ik leuk:

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

Sneller

Dat gezegd hebbende, zou ik format() . gebruiken en concat() en target de catalogustabel pg_attribute in plaats daarvan:schoner, eenvoudiger, sneller. Maar niet overdraagbaar naar andere 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;

Produceert:

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

db<>fiddle hier

Met name, ...

  • ... u hoeft de tabelnaam maar één keer op te geven, eventueel schema-gekwalificeerd.
  • ... als de tabel niet bestaat, mislukt de query onmiddellijk met een handige foutmelding.
  • ... de naam van de uitvoertabel is alleen schema-gekwalificeerd en dubbel geciteerd waar nodig.
  • ... dit omvat ook character(N) (interne naam bpchar ).

Verder lezen:




  1. SQL-probleem met uitchecktijden

  2. Cumulatief totaal berekenen in MySQL

  3. Expertadviezen over een zeer groot aantal kolommen in een mySQL-tabel?

  4. Miljoenen records invoegen van lokale naar godaddy-hosting