sql >> Databasteknik >  >> RDS >> PostgreSQL

quote_ident() lägger inte till citattecken i kolumnnamnet först

Uteslut inte AS nyckelord för kolumnalias

Inte exakt. Det exploderar eftersom du har utelämnat sökordet AS där den inte bör utelämnas.

Detta fungerar:

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;

Producerar:

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

Vilket fungerar som förväntat i sin tur.

manualen om "Utelämna AS nyckelord" :

Det är OK att utelämna nyckelordet AS för tabellalias, men inte för kolumnalias.

first är inte ett reserverat ord i Postgres. (Det brukade vara "reserverat" i den gamla SQL-standarden SQL-92, men inte längre i standard SQL heller.) Det är "icke-reserverat" * att vara precis. Handboken :

Utelämnar AS gör det till ett sådant sammanhang.

quote_ident() fungerar tillförlitligt. Handboken:

format() med specifikationen %I gör detsamma.

Reserverade ord nämns inte, men citeras korrekt oavsett. För att vara exakt:alla nyckelord märkta med "reserverad" eller "(kan inte vara funktion eller typ)" i kolumnen "PostgreSQL" i SQL-nyckelord bord .

Jag skickar en dokumentationsbugg för att lägga till det.

För att vara helt säker:quote_all_identifiers

Om du vill vara helt säker och inte har något emot allt extra brus, kan du tvinga Postgres att citera alla identifierare med konfigurationsparametern quote_all_identifiers . Handboken:

Det inkluderar utdata från quote_ident() och format() . Jag skulle inte gör det, fruktar allt extra brus.

Du kan ställa in parametern lokalt med SET LOCAL i samma transaktion. Gilla:

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

Snabbare

Som sagt, jag skulle använda format() och concat() och rikta in sig på katalogtabellen pg_attribute istället:renare, enklare, snabbare. Men inte portabel till andra 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;

Producerar:

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

db<>fiol här

Särskilt ...

  • ... du behöver bara ange tabellnamnet en gång, eventuellt schemakvalificerat.
  • ... om tabellen inte finns, misslyckas frågan omedelbart med ett användbart felmeddelande.
  • ... namnet på utdatatabellen är endast schemakvalificerat och citeras vid behov.
  • ... detta omfattar även character(N) (internt namn bpchar ).

Mer läsning:




  1. datetimeoffset hibernate mappning

  2. SQL Server sp_msforeachtable användning för att välja endast de tabeller som uppfyller något villkor

  3. Frågan går snabbt, men går långsamt i lagrad procedur

  4. mysqldump via SSH till lokal dator