DROP CASCADE в SQL Server - PullRequest
       5

DROP CASCADE в SQL Server

3 голосов
/ 28 сентября 2010

Я выполняю миграцию на юг в проекте Django, который использует Sql Server и pyodbc. Это обратная миграция, поэтому Юг пытается удалить несколько моих таблиц.

Юг выполняет следующий метод для удаления таблиц:

def delete_table(self, table_name, cascade=True):
    """
    Deletes the table 'table_name'.
    """
    params = (self.quote_name(table_name), )
    if cascade:
        self.execute('DROP TABLE %s CASCADE;' % params)
    else:
        self.execute('DROP TABLE %s;' % params)

drop_table = alias('delete_table')

Проблема в том, что сервер Sql не поддерживает каскадные отбрасывания, поэтому миграция завершается с ошибкой:

pyodbc.ProgrammingError: ('42000', "[42000] [Microsoft][ODBC SQL Server Driver][SQL Server]Incorrect syntax near the keyword 'CASCADE'. (156) (SQLExecDirectW)")

Я хочу написать патч для юга, чтобы он работал с Sql Server. Каков наилучший способ симулировать DROP CASCADE? Я думаю, что оба решения, использующие Python или чистый SQL, были бы правильными.

Ответы [ 2 ]

2 голосов
/ 30 сентября 2010

Я так и не нашел реализацию DROP CASCADE в python, поэтому я написал свою собственную.Вот как это выглядит:

def delete_table(self, table_name, cascade=True):
    """
    Deletes the table 'table_name'.
    """
    params = (self.quote_name(table_name), )
    if cascade:
        conn = self._get_connection()

        # Get a list of related tables
        sql = "SELECT T1.TABLE_NAME \
                 FROM INFORMATION_SCHEMA.CONSTRAINT_TABLE_USAGE AS T1 \
                 JOIN SYS.FOREIGN_KEYS AS F \
                   ON (F.parent_object_id = OBJECT_ID(N'{0}') OR \
                      F.referenced_object_id = OBJECT_ID(N'{0}')) AND \
                      T1.CONSTRAINT_NAME = OBJECT_NAME(F.object_id)"

        related_tables = self.execute(sql.format(params[0]))

        # Drop all the constraints
        constraints = self.execute("SELECT CONSTRAINT_NAME \
                                    FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS \
                                    WHERE TABLE_NAME='{0}' AND \
                                    CONSTRAINT_TYPE='FOREIGN KEY';".format(table_name))

        sql = "ALTER TABLE {0} DROP CONSTRAINT {1};"
        for constraint in constraints:
            self.execute(sql.format(params[0], constraint[0]))

        for table in related_tables:
            self.delete_table(table[0], cascade)

        sql = "IF  EXISTS (SELECT * \
                           FROM sys.objects \
                           WHERE object_id = OBJECT_ID(N'{0}') AND \
                           type in (N'U')) \
               DROP TABLE {0}"

        self.execute(sql.format(params[0]))
    else:
        self.execute('DROP TABLE %s;' % params)
1 голос
/ 28 сентября 2010

Что вы подразумеваете под "симулировать" КАПЕЛЬ КАПЕЛЬ?

Если это означает «игнорировать параметр каскада для MSSQL», тогда вы можете просто проверить текущую используемую платформу / диалект SQL и делать все, что вам нравится (я понятия не имею, как / если это возможно). Реализация sqlalchemy диалектов может дать вам несколько полезных идей, если они вам нужны.

Но если вы действительно хотите реализовать эту функциональность, вам придется запросить системные представления, чтобы создать список таблиц для удаления и правильный порядок их удаления. Документация для представлений INFORMATION_SCHEMA или sys.foreign_keys должна помочь , Как только у вас появится запрос, чтобы получить зависимые таблицы в правильном порядке, вы можете исправить функцию, чтобы она выполняла фактические DROP.

...