Schema names in psycopg2 identifiers

Question:

I want to use the sql submodule of psycopg2 to write clean dynamic SQL:

from psycopg2 import sql
...
cursor.execute(sql.SQL("SELECT * FROM {}").format(sql.Identifier('myschema.mytable'))

This creates the following query:

SELECT * FROM "myschema.mytable"

Here I get an Relation "myschema.mytable" not found. exception.

How do I handle the schema name properly? The following statements would work, but how do I create them with psycopg2?

SELECT * FROM myschema.mytable
SELECT * FROM myschema."mytable"
SELECT * FROM "myschema"."mytable"

edit: clarified schema prefix

Asked By: Max

||

Answers:

But the table in my PostgreSQL database is unquoted on purpose. This means mytable exists, but “mytable” does not.

You misunderstand what quotes do. In your case (i.e. a case without special characters in table name) the only thing double quotes do is they make the name case sensitive. If you have table with name MyTable then

SELECT * FROM mytable;

works because it is case insensitive while

SELECT * FROM "mytable";

does not because it is case sensitive. However

SELECT * FROM "MyTable";

will work and this is what you are looking for.


The other problem (as noted by @IljaEverilä in comments) is this:

SELECT * FROM "myschema.mytable"

which postgres treats as a table with name myschema.mytable because you’ve quoted the whole thing. I assume this is what you are looking for:

SELECT * FROM "myschema"."mytable"

i.e. you need a separate identifier for schema and seperate for table joined by ..

Answered By: freakish

The construction

sql.Identifier('myschema.mytable')

is treated as a single quoted identifier, as can be seen from the produced query. You should pass the schema and table name as separate identifiers to format:

cursor.execute(sql.SQL("SELECT * FROM {}.{}").format(
    sql.Identifier('myschema'),
    sql.Identifier('mytable'))

Note that the schema and table name must match exactly, case and all, since psycopg2‘s SQL string composition tools produce quoted identifiers, and quoted identifiers are case-sensitive.

Answered By: Ilja Everilä

Since version 2.8 (released in Apr 4, 2019), you can pass multiple strings to sql.Identifier to represent a qualified identifier (e.g. a schema name + a table name).

cursor.execute(
    sql.SQL("SELECT * FROM {table}").format(
        table=sql.Identifier("myschema", "mytable")
    )
)

# SELECT * FROM "myschema"."mytable"

See: https://www.psycopg.org/docs/sql.html#psycopg2.sql.Identifier

Answered By: GG.
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.