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

quote_ident() tilføjer ikke anførselstegn til kolonnenavnet først

Undlad ikke AS nøgleord for kolonnealiasser

Ikke nøjagtigt. Det sprænger, fordi du har udeladt søgeordet AS hvor det ikke bør udelades.

Dette virker:

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;

Producerer:

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

Hvilket til gengæld fungerer som forventet.

manualen om "Udeladelse af AS nøgleord" :

Det er OK at udelade søgeordet AS for tabelaliasser, men ikke for kolonnealiasser.

first er ikke et reserveret ord i Postgres. (Det plejede at være "reserveret" i den gamle SQL-standard SQL-92, men heller ikke længere i standard SQL.) Det er "ikke-reserveret" * for at være præcis. Manualen :

Udeladelse af AS gør det til netop sådan en sammenhæng.

quote_ident() fungerer pålideligt. Manualen:

format() med specifikationen %I gør det samme.

Reserverede ord nævnes ikke, men citeres korrekt uanset. For at være præcis:alle nøgleord markeret med "reserveret" eller "(kan ikke være funktion eller type)" i kolonnen "PostgreSQL" i SQL-nøgleord bord .

Jeg indsender en dokumentationsfejl for at tilføje det.

For at være helt sikker:quote_all_identifiers

Hvis du vil være helt sikker og ikke har noget imod al den ekstra støj, kan du tvinge Postgres til at citere alle identifikatorer med konfigurationsparameteren quote_all_identifiers . Manualen:

Det inkluderer output fra quote_ident() og format() . Jeg ville ikke gør det, frygter al den ekstra støj.

Du kan indstille parameteren lokalt med SET LOCAL i samme transaktion. Ligesom:

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

Hurtigere

Når det er sagt, ville jeg bruge format() og concat() og målretter mod katalogtabellen pg_attribute i stedet:renere, enklere, hurtigere. Men ikke bærbar til andre 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;

Producerer:

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

db<>fiddle her

Især ...

  • ... du behøver kun at angive tabelnavnet én gang, eventuelt skema-kvalificeret.
  • ... hvis tabellen ikke eksisterer, mislykkes forespørgslen med det samme med en nyttig fejlmeddelelse.
  • ... outputtabelnavnet er kun skema-kvalificeret og citeret med dobbelte anførselstegn, hvor det er nødvendigt.
  • ... dette dækker også character(N) (internt navn bpchar ).

Yderligere læsning:




  1. Er det en god idé at bruge Hibernate til at repræsentere tabelrelationer?

  2. Oracle SQL dyb opdatering

  3. Er der en måde at indlæse tekstdata til databasen i PostgreSQL?

  4. mysql tabel struktur forslag?