Проблема выполнения необработанного SQL-запроса в Python: ошибка синтаксиса sqlalchemy.exc.programmingerror в или около - PullRequest
1 голос
/ 12 октября 2019

У меня есть запрос в скрипте Python, который создает материализованное представление после создания некоторых таблиц.

Сценарий выглядит примерно так:

    from sqlalchemy import create_engine, text

    sql = '''CREATE MATERIALIZED VIEW schema1.view1 AS 
            SELECT t1.a,
              t1.b,
              t1.c,
              t2.x AS d
            FROM schema1.t1 t1
            LEFT JOIN schema1.t2 t2 ON t1.f = t2.f
            UNION ALL
            SELECT t3.a, 
              t3.b, 
              t3.c, 
              t3.d
            FROM schema1.t3 t3;'''

    con=create_engine(db_conn)

    con.execute(sql)

Запрос успешно выполняется при запускенепосредственно в базе данных.

Но при запуске сценария на python я получаю сообщение об ошибке:

sqlalchemy.exc.ProgrammingError: (psycopg2.errors.SyntaxError) syntax error at or near "CREATE MATERIALIZED VIEW schema"

Не могу понять, с чем у него проблема- есть идеи?

Ответы [ 2 ]

1 голос
/ 14 октября 2019

Это была самая странная вещь. Я скопировал текст моего запроса из другого инструмента, который я использую для навигации по моей pg DB в VS Code. Последняя часть ответа @EOhm дала мне идею просто напечатать все это в VS Code вместо копирования / вставки.

И все заработало.

Несмотря на то, что вставленный текст и то, что я напечатал, во всех отношениях идентичны. Так что, по-видимому, возникла невидимая форма форматирования, вызывающая эту проблему.

0 голосов
/ 12 октября 2019

Я не знаю, поддерживает ли SQLAlchemy MView-Creation, но если оно должно быть похоже или выполнено с определенными функциями метаданных (https://docs.sqlalchemy.org/en/13/core/schema.html).

Текстовая функция предназначена для независимой от базы данных DML,не DDL. Возможно, это работает для DDL (я не знаю о SQLAlchemy), но по своей структуре синтаксис отличается от того, когда вы выполняете непосредственно в базе данных, поскольку SQLAlchemy должен абстрагировать детали баз данных от пользователя.

Если SQLAlchemy не предлагает какого-либо удобного способа для этого, и у вас, тем не менее, есть веские причины вообще использовать SQLAlchemy, вы можете просто выполнить простой SQL Statememt на диалекте, который понимает бэкэнд базы данных, поэтому просто опустите функцию sqlalchemies text для SQLоператор, например:

   from sqlalchemy import create_engine, text

    sql = '''CREATE MATERIALIZED VIEW schema.view1 AS 
            SELECT t1.a,
              t1.b,
              t1.c
              t2.x AS d
            FROM schema.t1 t1
            LEFT JOIN schema.t2 t2 ON t1.f = t2.f
            UNION ALL
            SELECT t3.a, 
              t3.b, 
              t3.c, 
              t3.d
            FROM schema.t3 t3;'''

    con=create_engine(db_conn)
    con.raw_connection().cursor().execute(sql)

(Но, конечно, вы должны позаботиться о типе бэкэнда, а не обернутых операторов SQLAlchemy.)


Я тестировал на своем сервере pgбез каких-либо проблем, используя psycopg2 напрямую.

postgres=# create schema schema;
CREATE TABLE
postgres=# create table schema.t1 (a varchar, b varchar, c varchar, f integer);
CREATE TABLE
postgres=# create table schema.t2 (x varchar, f integer);
CREATE TABLE
postgres=# create table schema.t3 (a varchar, b varchar, c varchar, d varchar);
CREATE TABLE
postgres=# commit;

со следующимскрипт:

#!/usr/bin/python3
import psycopg2;

conn = psycopg2.connect("dbname=postgres")
cur = conn.cursor()
cur.execute("""
            CREATE MATERIALIZED VIEW schema.view1 AS
            SELECT t1.a,
              t1.b,
              t1.c,
              t2.x AS d
            FROM schema.t1 t1
            LEFT JOIN schema.t2 t2 ON t1.f = t2.f
            UNION ALL
            SELECT t3.a,
              t3.b,
              t3.c,
              t3.d
            FROM schema.t3 t3;
""")
conn.commit()
cur.close()
conn.close()

Я тестировал с довольно актуальными версиями python3.7 / 2.7 и текущей версией модуля psycopg2 и текущими библиотеками (у меня есть 11.5 pg client и 2.8.3 psycopg2) из ​​pgdg, установленной на довольнонедавний linux? Можете ли вы попробовать выполнить прямо на psycopg2, как я?

Также Вы убедились, что Ваши точки являются простыми точками ascii, как и все остальные символы в выражении в этом случае? (Также имейте в виду, что в Unicode могут быть невидимые кодовые точки, которые могут вызвать такие проблемы.) Возможно, Вы можете преобразовать свою строку в двоичный файл ASCII и обратно в Unicode-String, если вы находитесь на Python. Если это не вызывает ошибку на .encode('ASCII'), она должна быть чистой.

...