【问题标题】:How to drop all tables and reset an Azure SQL Database如何删除所有表并重置 Azure SQL 数据库
【发布时间】:2023-04-01 08:45:01
【问题描述】:

我有一个本地工作的 ASP.NET MVC 5 项目,每当我需要删除数据库时,我只需在其上打开一个新查询,将可用数据库下拉列表更改为 master,然后关闭本地数据库上的连接并运行查询“drop database [name]”。然后我构建项目,进入包管理器控制台并运行“更新数据库”。这似乎重建了一个新的本地数据库并在我的 configuration.cs 文件中运行种子方法。

问题是当我需要在实时环境中测试事物以便我可以更好地测试 API 时,我将部署到 Azure 网站和随附的 Azure DB,这很好而且很容易做到。我在发布向导中检查了“执行代码优先迁移”,大部分时间它都可以工作,我可以运行和调试我的实时版本。有时我需要删除该数据库并重新从头开始,但我真正找到的唯一方法是进入 Azure 门户,删除数据库,然后使用相同的名称重新创建它。 Azure 需要一些时间来处理,因此这是一个缓慢的测试周期。

有没有一种快速的方法可以将 Azure SQL DB 删除/重置为新鲜、空的、原始状态,然后使用“执行代码优先迁移”重新发布,让它重新创建表并重新- 播种数据?

我看到一些关于在创建数据库后创建初始迁移的讨论,然后尝试使用 Powershell 进行某种回滚到该初始状态,但我没有运气让它工作,我想同时删除所有数据。也许我只是语法错误,或者没有找到足够好的教程。虽然我可以在 Azure DB 上运行查询以“删除数据库 [x]”,但它实际上会按照您的预期杀死 SQL Azure DB 实例,您需要返回门户重新创建它。有时初始状态并不好,因为模型已经更新,所以无论如何这可能没有用。

我觉得应该有一些更简单快捷的方法来测试实时环境中的更改,因为 MS 提供了所有这些很棒的工具和快捷方式,但是他们只是在这个开发阶段把球丢在这里还是我错过了什么?

【问题讨论】:

    标签: c# asp.net visual-studio azure azure-sql-database


    【解决方案1】:

    除了@Gizmo3399 给出的答案。我们使用带有Entity Framework (EF) Core 5.0.2.NET 5 的时态表。这是我们用来清除数据库的命令。 History 是我们用于系统版本化时态表的模式。目前需要运行两次才能删除所有内容,但不需要进行任何修改。

    /* Azure friendly */
    /* Drop all Foreign Key constraints */
    DECLARE @name VARCHAR(128)
    DECLARE @constraint VARCHAR(254)
    DECLARE @SQL VARCHAR(254)
    DECLARE @SQL2 VARCHAR(254)
    
    SELECT @name = (SELECT TOP 1 TABLE_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE constraint_catalog=DB_NAME() AND CONSTRAINT_TYPE = 'FOREIGN KEY' ORDER BY TABLE_NAME)
    
    WHILE @name is not null
    BEGIN
        SELECT @constraint = (SELECT TOP 1 CONSTRAINT_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE constraint_catalog=DB_NAME() AND CONSTRAINT_TYPE = 'FOREIGN KEY' AND TABLE_NAME = @name ORDER BY CONSTRAINT_NAME)
        WHILE @constraint IS NOT NULL
        BEGIN
            IF EXISTS (SELECT * FROM sys.schemas WHERE name = 'History') AND @name != '__EFMigrationsHistory'
                BEGIN
                     SELECT @SQL = 'ALTER TABLE [history].[' + RTRIM(@name) +'] DROP CONSTRAINT [' + RTRIM(@constraint) +']'
                     EXEC (@SQL)
                END
            SELECT @SQL2 = 'ALTER TABLE [dbo].[' + RTRIM(@name) +'] DROP CONSTRAINT [' + RTRIM(@constraint) +']'
            EXEC (@SQL2)
            PRINT 'Dropped FK Constraint: ' + @constraint + ' on ' + @name
            SELECT @constraint = (SELECT TOP 1 CONSTRAINT_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE constraint_catalog=DB_NAME() AND CONSTRAINT_TYPE = 'FOREIGN KEY' AND CONSTRAINT_NAME <> @constraint AND TABLE_NAME = @name ORDER BY CONSTRAINT_NAME)
        END
    SELECT @name = (SELECT TOP 1 TABLE_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE constraint_catalog=DB_NAME() AND CONSTRAINT_TYPE = 'FOREIGN KEY' ORDER BY TABLE_NAME)
    END
    GO
    
    /* Drop all Primary Key constraints */
    DECLARE @name VARCHAR(128)
    DECLARE @constraint VARCHAR(254)
    DECLARE @SQL VARCHAR(254)
    DECLARE @SQL2 VARCHAR(254)
    
    SELECT @name = (SELECT TOP 1 TABLE_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE constraint_catalog=DB_NAME() AND CONSTRAINT_TYPE = 'PRIMARY KEY' ORDER BY TABLE_NAME)
    
    WHILE @name IS NOT NULL
    BEGIN
        SELECT @constraint = (SELECT TOP 1 CONSTRAINT_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE constraint_catalog=DB_NAME() AND CONSTRAINT_TYPE = 'PRIMARY KEY' AND TABLE_NAME = @name ORDER BY CONSTRAINT_NAME)
        WHILE @constraint is not null
        BEGIN
            IF EXISTS (SELECT * FROM sys.schemas WHERE name = 'History') AND @name != '__EFMigrationsHistory'
                BEGIN
                    SELECT @SQL = 'ALTER TABLE [history].[' + RTRIM(@name) +'] DROP CONSTRAINT [' + RTRIM(@constraint)+']'
                    EXEC (@SQL)
                END
            SELECT @SQL2 = 'ALTER TABLE [dbo].[' + RTRIM(@name) +'] DROP CONSTRAINT [' + RTRIM(@constraint) +']'
            EXEC (@SQL2)
            PRINT 'Dropped PK Constraint: ' + @constraint + ' on ' + @name
            SELECT @constraint = (SELECT TOP 1 CONSTRAINT_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE constraint_catalog=DB_NAME() AND CONSTRAINT_TYPE = 'PRIMARY KEY' AND CONSTRAINT_NAME <> @constraint AND TABLE_NAME = @name ORDER BY CONSTRAINT_NAME)
        END
    SELECT @name = (SELECT TOP 1 TABLE_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE constraint_catalog=DB_NAME() AND CONSTRAINT_TYPE = 'PRIMARY KEY' ORDER BY TABLE_NAME)
    END
    GO
    
    /* Drop all tables */
    DECLARE @name VARCHAR(128)
    DECLARE @SQL VARCHAR(254)
    DECLARE @SQL2 VARCHAR(254)
    DECLARE @SQL3 VARCHAR(254)
    
    SELECT @name = (SELECT TOP 1 [name] FROM sysobjects WHERE [type] = 'U' AND category = 0 ORDER BY [name])
    
    WHILE @name IS NOT NULL
    BEGIN
        IF EXISTS (SELECT * FROM sys.schemas WHERE name = 'History') AND @name != '__EFMigrationsHistory'
            BEGIN
                SELECT @SQL = ('ALTER TABLE [' + RTRIM(@name) +'] SET (SYSTEM_VERSIONING = OFF)');
                EXEC (@SQL)
                SELECT @SQL2 = 'DROP TABLE [history].[' + RTRIM(@name) +']'
                EXEC (@SQL2)
            END
        SELECT @SQL3 = 'DROP TABLE [dbo].[' + RTRIM(@name) +']'
        EXEC (@SQL3)
        PRINT 'Dropped Table: ' + @name
        SELECT @name = (SELECT TOP 1 [name] FROM sysobjects WHERE [type] = 'U' AND category = 0 AND [name] > @name ORDER BY [name])
    END
    GO
    
    IF EXISTS (SELECT * FROM sys.schemas WHERE name = 'History')
    BEGIN
        DROP SCHEMA History
    END
    
    GO
    

    【讨论】:

      【解决方案2】:

      只是将我的变体添加到组合中...这个还考虑了视图和外部表。它不会对必须使用 DROP EXTERNAL TABLE 单独删除的外部表产生影响。这导致原始版本永远旋转。

      while(exists(select 1 from INFORMATION_SCHEMA.TABLE_CONSTRAINTS where CONSTRAINT_TYPE='FOREIGN KEY'))
      begin
       declare @sql nvarchar(2000)
       SELECT TOP 1 @sql=('ALTER TABLE ' + TABLE_SCHEMA + '.[' + TABLE_NAME
       + '] DROP CONSTRAINT [' + CONSTRAINT_NAME + ']')
       FROM information_schema.table_constraints
       WHERE CONSTRAINT_TYPE = 'FOREIGN KEY'
       exec (@sql)
       PRINT @sql
      end
      
      
      while(exists(select 1 from INFORMATION_SCHEMA.TABLES 
          where TABLE_NAME != 'database_firewall_rules' 
          AND TABLE_TYPE = 'BASE TABLE'
          AND TABLE_NAME NOT IN (select name from sys.external_tables)))
      begin
       declare @sql1 nvarchar(2000)
       SELECT TOP 1 @sql1=('DROP TABLE ' + TABLE_SCHEMA + '.[' + TABLE_NAME + ']')
       FROM INFORMATION_SCHEMA.TABLES
       WHERE TABLE_NAME != 'database_firewall_rules'
          AND TABLE_TYPE = 'BASE TABLE'
          AND TABLE_NAME NOT IN (select name from sys.external_tables)
      exec (@sql1)
       PRINT @sql1
      end
      

      【讨论】:

        【解决方案3】:

        Azure SQL 本质上是 SQL 服务器。所以你可以使用 MS SQL Server Management Studio https://docs.microsoft.com/en-us/sql/ssms/download-sql-server-management-studio-ssms

        使用您的管理员帐户在 Management Studio 中打开数据库,然后执行 drop table SQL 命令或使用 GUI 右键菜单做任何您想做的事情,就像使用本地数据库一样。

        可以在 Visual Studio SQL Server 对象资源管理器中完成类似的操作。只需右键单击根“添加 SQL 服务器”。

        【讨论】:

          【解决方案4】:

          只是为了添加答案,因为接受的答案在 Azure 上对我不起作用。 使用以下脚本删除所有表并基本上重置 azure 数据库。 它首先删除所有约束,然后删除所有表。

          正如@Skorunka František 所说,此脚本假定您使用默认的 [dbo] 架构。尽管您可以将其替换为您自己的架构名称。

          /* Azure friendly */
          /* Drop all Foreign Key constraints */
          DECLARE @name VARCHAR(128)
          DECLARE @constraint VARCHAR(254)
          DECLARE @SQL VARCHAR(254)
          
          SELECT @name = (SELECT TOP 1 TABLE_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE constraint_catalog=DB_NAME() AND CONSTRAINT_TYPE = 'FOREIGN KEY' ORDER BY TABLE_NAME)
          
          WHILE @name is not null
          BEGIN
              SELECT @constraint = (SELECT TOP 1 CONSTRAINT_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE constraint_catalog=DB_NAME() AND CONSTRAINT_TYPE = 'FOREIGN KEY' AND TABLE_NAME = @name ORDER BY CONSTRAINT_NAME)
              WHILE @constraint IS NOT NULL
              BEGIN
                  SELECT @SQL = 'ALTER TABLE [dbo].[' + RTRIM(@name) +'] DROP CONSTRAINT [' + RTRIM(@constraint) +']'
                  EXEC (@SQL)
                  PRINT 'Dropped FK Constraint: ' + @constraint + ' on ' + @name
                  SELECT @constraint = (SELECT TOP 1 CONSTRAINT_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE constraint_catalog=DB_NAME() AND CONSTRAINT_TYPE = 'FOREIGN KEY' AND CONSTRAINT_NAME <> @constraint AND TABLE_NAME = @name ORDER BY CONSTRAINT_NAME)
              END
          SELECT @name = (SELECT TOP 1 TABLE_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE constraint_catalog=DB_NAME() AND CONSTRAINT_TYPE = 'FOREIGN KEY' ORDER BY TABLE_NAME)
          END
          GO
          
          /* Drop all Primary Key constraints */
          DECLARE @name VARCHAR(128)
          DECLARE @constraint VARCHAR(254)
          DECLARE @SQL VARCHAR(254)
          
          SELECT @name = (SELECT TOP 1 TABLE_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE constraint_catalog=DB_NAME() AND CONSTRAINT_TYPE = 'PRIMARY KEY' ORDER BY TABLE_NAME)
          
          WHILE @name IS NOT NULL
          BEGIN
              SELECT @constraint = (SELECT TOP 1 CONSTRAINT_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE constraint_catalog=DB_NAME() AND CONSTRAINT_TYPE = 'PRIMARY KEY' AND TABLE_NAME = @name ORDER BY CONSTRAINT_NAME)
              WHILE @constraint is not null
              BEGIN
                  SELECT @SQL = 'ALTER TABLE [dbo].[' + RTRIM(@name) +'] DROP CONSTRAINT [' + RTRIM(@constraint)+']'
                  EXEC (@SQL)
                  PRINT 'Dropped PK Constraint: ' + @constraint + ' on ' + @name
                  SELECT @constraint = (SELECT TOP 1 CONSTRAINT_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE constraint_catalog=DB_NAME() AND CONSTRAINT_TYPE = 'PRIMARY KEY' AND CONSTRAINT_NAME <> @constraint AND TABLE_NAME = @name ORDER BY CONSTRAINT_NAME)
              END
          SELECT @name = (SELECT TOP 1 TABLE_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE constraint_catalog=DB_NAME() AND CONSTRAINT_TYPE = 'PRIMARY KEY' ORDER BY TABLE_NAME)
          END
          GO
          
          /* Drop all tables */
          DECLARE @name VARCHAR(128)
          DECLARE @SQL VARCHAR(254)
          
          SELECT @name = (SELECT TOP 1 [name] FROM sysobjects WHERE [type] = 'U' AND category = 0 ORDER BY [name])
          
          WHILE @name IS NOT NULL
          BEGIN
              SELECT @SQL = 'DROP TABLE [dbo].[' + RTRIM(@name) +']'
              EXEC (@SQL)
              PRINT 'Dropped Table: ' + @name
              SELECT @name = (SELECT TOP 1 [name] FROM sysobjects WHERE [type] = 'U' AND category = 0 AND [name] > @name ORDER BY [name])
          END
          GO
          

          遗憾的是,我无法再找到此代码的源代码,因为我已将它保存在我的一个存储库中。 我希望它可以帮助某人。

          【讨论】:

          • 如果您不使用默认的“dbo”架构,上述方法将不起作用。
          • 我刚刚声明了一个模式变量并在 where 子句中添加了 'AND CONSTRAINT_SCHEMA = @Schema'
          • 好的,这在我无权删除数据库的服务器上对我有用。谢谢
          • 在 Azure SQL 上运行良好。感谢您发布 Gizmo3399!
          • 这对我来说就像在 Azure SQL 数据库上的魅力一样。非常感谢!
          【解决方案5】:

          我经常

          1. 打开 SQL Server Management Studio 或从 Visual Studio 打开 SQL Server 对象资源管理器
          2. 我连接到 Azure SQL Server(即:yourserver.database.windows.net 并选择了 SQL Server 身份验证选项的用户名和密码)(还请记住,您需要在 Azure 门户中添加防火墙例外才能从您的 PC 连接到数据库)
          3. 右键单击数据库并删除。

          就这么简单。

          然后,由于您提到您有代码优先迁移方法,只需在 Azure SQL Server 中再次运行迁移(例如,在发布时请确保选中为给定 sql server 连接字符串应用迁移的选项)

          我通常删除远程数据库,然后使用命令重新部署应用程序以重新运行迁移。这将使用新表再次创建数据库。为数据库播种的代码在我的启动代码中,因此如果 DB 中没有值,则在应用程序初始化的任何时候都会播种。

          这对 AspNet Core Mvc (MVC6) 也有效

          【讨论】:

          • 我认为这对 Azure SQL 不起作用,至少对我不起作用。我不得不再次在 Azure 门户中创建数据库。
          • 奇怪,几分钟前我试过了。在 MSSMS 中删除了数据库,然后尝试运行迁移并获得用户“cat'n access provided database”错误或类似错误。
          • 我正在使用 Asp.Net Core 和 EF Core,并在发布时通过 Visual Studio 应用迁移(通过选中应用迁移选项)。也许您正在使用 EF 6?如果是这样,您可能必须运行Add-Migration InitialCreate 来指定数据库不存在并且您想再次创建它。不过没试过。
          • 永远不要让任何工具自动为您创建 Azure 数据库。默认数据库非常昂贵。相反,请使用 Azure 门户创建数据库,以便仔细检查所选计划。然后您可以将您的应用指向它以运行迁移等。
          【解决方案6】:

          据我所知,由于没有 API 方法可以执行此操作,因此我们使用了this script to leverage a T-SQL query to clear the database

          删除每个表(并根据需要维护您的 EF 迁移历史记录)

          while(exists(select 1 from INFORMATION_SCHEMA.TABLES 
                       where TABLE_NAME != '__MigrationHistory' 
                       AND TABLE_TYPE = 'BASE TABLE'))
          begin
           declare @sql nvarchar(2000)
           SELECT TOP 1 @sql=('DROP TABLE ' + TABLE_SCHEMA + '.[' + TABLE_NAME
           + ']')
           FROM INFORMATION_SCHEMA.TABLES
           WHERE TABLE_NAME != '__MigrationHistory' AND TABLE_TYPE = 'BASE TABLE'
          exec (@sql)
           /* you dont need this line, it just shows what was executed */
           PRINT @sql
          end
          

          如果需要,先删除外键

          while(exists(select 1 from INFORMATION_SCHEMA.TABLE_CONSTRAINTS where CONSTRAINT_TYPE='FOREIGN KEY'))
          begin
           declare @sql nvarchar(2000)
           SELECT TOP 1 @sql=('ALTER TABLE ' + TABLE_SCHEMA + '.[' + TABLE_NAME
           + '] DROP CONSTRAINT [' + CONSTRAINT_NAME + ']')
           FROM information_schema.table_constraints
           WHERE CONSTRAINT_TYPE = 'FOREIGN KEY'
           exec (@sql)
           PRINT @sql
          end
          

          在我的测试中,这没有问题(除了我在查询时在 DROP TABLE 中没有 where 子句,因为我不使用 Code First 或 EF 迁移)。

          【讨论】:

          • 这似乎在 Azure 上不起作用,它删除了 1/8 的表格然后永远旋转,当我点击停止时,我看到一堆错误,它无权删除一些特殊的表。外键似乎可以运行,但对其他问题并没有真正帮助。
          • @Ivan - 我发现了问题,WHERE 子句不正确,您还必须按TABLE_TYPE 过滤。检查更新并让我知道您是否仍有问题?
          • 它就像在 Azure 的 sql server 上运行的魅力一样!
          • 小心,INFORMATION_SCHEMA.TABLES 有时会以行的形式返回 View 对象,从而使 while 永远循环(因为它们永远不会被删除)。最好使用 Gizmo 答案!
          • @izio Gizmo 不适用于遵循不使用 dbo 的良好做法的任何业务。它可以很容易地适应,但我只想指出,这样人们就不会忽视这个答案。
          【解决方案7】:

          或者,您可以在 C# 中删除数据库并使用 ExecuteNonQuery 创建一个新数据库。

          queryString = "DROP DATABASE TestDB2";
          
          SqlCommand command = new SqlCommand(queryString, connection);
                  command.Connection.Open();
                  command.ExecuteNonQuery();
          

          其中 connection 是与 Azure SQL 数据库主数据库的连接。

          或者,创建一个数据库:

          queryString = "CREATE DATABASE TestDB2 ( EDITION = 'standard' )";
          

          【讨论】:

          • 我该怎么做?Azure 会允许我从 C# 创建一个新数据库吗?
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-08-09
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多