SQL ALTER и DROP база данных, если существует с PYODBC - PullRequest
1 голос
/ 19 марта 2020

Как SQL newb ie, я пытаюсь убедиться, что при первоначальном импорте данных в базу данных не будут создаваться дублированные записи, и базы данных будут создаваться программно. Я не удивлюсь, если есть более эффективный способ сделать это (скажи!), Но мой метод - удалить базу данных и воссоздать ее, если она уже существует, что, насколько я могу судить, очень быстро. Я успешно использовал этот же оператор вне функции и без форматированной строки, но при создании функции для этого я получаю сообщение об ошибке через PYODB C:

ProgrammingError: ('42S22', "[42S22] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]Invalid column name 'test'. (207) (SQLExecDirectW)")

Это сбивает с толку, так как я не пытаюсь ссылаться на какие-либо столбцы, не говоря уже о таблицах; так что это затрудняет поиск и устранение неисправностей. Функции следующие:

def db_connect(db, driver='ODBC Driver 17 for SQL Server', host='', UID='', PWD='', autocommit=False):
    """Returns a connection and a cursor object for the specified database."""
    conn = pyodbc.connect(driver=driver,
                        host=host,
                        database=db,
                        UID=UID,
                        PWD=PWD,
                        autocommit=autocommit
                        )
    print(f'Connect established to database {db}')
    return conn, conn.cursor()

def db_clear(db, recreate=True):
    """Drops and recreates the specified database, ready for insert."""
    conn, curs = db_connect('master')
    curs.execute(f"""IF EXISTS (SELECT name from sys.databases WHERE (name = {db}))
        BEGIN
            ALTER DATABASE {db} SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
            DROP DATABASE {db};
        END;""")
    if recreate:
        curs.execute(f"CREATE DATABASE {db};")
        conn.close()
        print(f'{db} successfully dropped and recreated.')
    else:
        print(f'{db} successfully dropped.')
    return

db_clear('test')

Исключение возникает в строке, содержащей END;"""). Есть только два различия между рабочей версией (не содержащейся в функции) и этой версией функции, в том, что я начал использовать более новый драйвер для лучшей обработки преобразований типов данных и отключил автокоммит для вставки в пакеты после выполнения этих функций. их работы. Я попытался вернуть обе эти опции к исходным настройкам в функции, но получил ту же ошибку. Любая помощь приветствуется!

1 Ответ

0 голосов
/ 20 марта 2020

Форматирование вашей строки

f"""IF EXISTS (SELECT name from sys.databases WHERE (name = {db}))
    BEGIN
        ALTER DATABASE {db} SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
        DROP DATABASE {db};
    END;"""

производит

IF EXISTS (SELECT name from sys.databases WHERE (name = test))
BEGIN
    ALTER DATABASE test SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
    DROP DATABASE test;
END;

, и когда анализатор SQL видит WHERE (name = test), он интерпретирует test как имя столбца (в sys .databases (view / view)), так же как он (правильно) интерпретирует name как имя столбца.

Вместо этого вам нужно просто указать значение параметра в предложении WHERE :

sql = f"""IF EXISTS (SELECT name from sys.databases WHERE (name = ?))
          BEGIN
              ALTER DATABASE [{db}] SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
              DROP DATABASE [{db}];
          END;"""
curs.execute(sql, db)
...