【问题标题】:DROP CASCADE in Sql Server在 Sql Server 中删除 CASCADE
【发布时间】:2010-09-28 12:54:48
【问题描述】:

我正在使用 Sql Server 和 pyodbc 的 Django 项目中运行南迁移。这是向后迁移,所以南方试图删除我的一些表。

South 执行以下方法以删除表:

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 Server不支持cascade drop,所以迁移失败,报如下错误:

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

我想为 South 写一个补丁,以便它与 Sql Server 一起工作。模拟 DROP CASCADE 的最佳方法是什么?我认为使用 python 或纯 SQL 的两种解决方案都是有效的。

【问题讨论】:

    标签: sql-server django django-south


    【解决方案1】:

    我从未在 python 中找到 DROP CASCADE 的实现,所以我最终编写了自己的。这是它的外观:

    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)
    

    【讨论】:

      【解决方案2】:

      “模拟”DROP CASCADE 是什么意思?

      如果它的意思是“忽略 MSSQL 的级联参数”,那么您可以检查当前使用的 SQL 平台/方言并做任何您喜欢的事情(我不知道如何/是否可能)。如果你需要的话,sqlalchemy dialects implementation 可能会给你一些有用的想法。

      但是,如果您想实际实现该功能,您将查询系统视图以构建要删除的表的列表以及删除它们的正确顺序。INFORMATION_SCHEMA 视图或 sys.foreign_keys 的文档应该会有所帮助.一旦您有查询以正确顺序获取依赖表,您可以修补函数以执行实际的 DROP。

      【讨论】:

      • “模拟”是指我需要编写一个代码,如果 MSSQL 实现了 DROP CASCADE,它会做的事情。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-11-13
      • 1970-01-01
      • 2020-06-20
      • 2010-09-05
      • 2015-08-11
      相关资源
      最近更新 更多