【问题标题】:Change the ANSI_NULLS setting for all Stored Procedures in the Database更改数据库中所有存储过程的 ANSI_NULLS 设置
【发布时间】:2011-01-09 23:43:22
【问题描述】:

我们在 ANSI_NULLS 设置和计算列方面存在一些问题,并且我们有大量的存储过程具有

SET ANSI_NULLS OFF

我们想把它们全部改成

SET ANSI_NULLS ON

有没有一种简单的方法可以做到这一点,或者我必须将所有 SP 提取到一个脚本中,更改它并再次运行它以删除并重新创建所有 SPa

【问题讨论】:

    标签: sql-server stored-procedures


    【解决方案1】:

    只是想在那里发出警告。我无法想象为什么您为所有 SP 设置了 ansi_nulls,但是如果他们中的任何一个以任何方式依赖与 NULL 的比较(并且可能发生很多不同的方式),当您更改时,您的结果会有所不同那个设置。我建议在安全的环境中进行一些严格的回归测试。

    【讨论】:

    • @TG:感谢您的警告,所有这些存储过程都是自动生成的 CRUD 操作。我们有所有带有该选项的 SP,因为我们在模板 sql 中留下了 SET ANSI_NULLS OFF。程序非常简单,我们不涉及这个问题。
    • 我明白了——这是有道理的。如果您的代码生成器具有该 ansi_nulls 设置,那么它们当然都会以这种方式结束。那么很可能任何手动创建的 SP 都不会关闭 ansi_nulls。我猜如果任何生成的 SP 在可空列上都有 JOIN,那么唯一可能的“gottcha”会是。但听起来情况并非如此。继续:)
    【解决方案2】:

    您必须编写所有过程的脚本,并在启用 ANSI_NULLS 的情况下重新创建它们。

    如果我有很多要做,我可能会在我的客户端应用程序中添加一个功能。

    伪代码:

    procedure FixAllStoredProcedureAnsiNullness(connection)
    {
       Strings spNames = GetStoredProcedureNames(connection);
    
       foreach spName in spNames
       {
           String sql = GetStoredProcedureSQL(connection, spName);
    
           //turn on option for remainder of connection
           connection.ExecuteNoRecords("SET ANSI_NULLS ON"); 
    
           BeginTransaction(connection);
           try
              connection.ExecuteNoRecords("DROP PROCEDURE "+spName);
              connection.ExecuteNoRecords(sql);
              CommitTranasction(connection);
           except
              RollbackTransaction(connection);
              raise;
           end;
       }
    }
    

    我在SQL Server: How to generate object scripts without DMO/SMO? 上有关于如何以编程方式获取存储过程的 SQL 的代码

    但通常我只会使用 Enterprise Manager,从存储过程列表的顶部开始:

    1. 返回
    2. Ctrl+主页
    3. Ctrl+V
    4. 点击确定
    5. 关闭
    6. 转到 1

    我的剪贴板包含的位置:

    SET ANSI_NULLS ON
    GO
    

    如果你不幸被 SSMS 卡住了,那么你就是那个 POS 的 SOL,IIRC。 TWSS。

    【讨论】:

    • 非常感谢,我将使用这个 Sql 来获取所有失败的 SP 及其代码:选择 object_name(object_id) 作为名称,定义为来自 sys.all_sql_modules 的代码 where objectproperty([object_id] , 'IsProcedure') = 1 和 uses_ansi_nulls = 0
    • 我刚刚添加了 C# 代码来重新创建所有 sps :) 我们不能手动完成,因为我们有 8 个数据库,每个数据库都有近 500 个,所以感谢您指出如何自动化流程。跨度>
    • 已编辑伪代码:在连接上设置一次 ansi_nulls 选项 - 因为批处理中必须单独使用“CREATE PROC”。
    【解决方案3】:

    我们使用的解决方案是 Ian 发布的,现在我们有一个自动化程序来解决问题。

    这是我们用来从数据库中重新创建所有 SP 的最终代码:

    public static class AnsiNullsManager
    {
    
        public static void ReCreateAllStoredProcedures(SqlConnection connection, bool ansiNullsOn)
        {
            var sql =
                @"select object_name(sys.all_sql_modules.object_id) as Name, definition as Code
                    from sys.all_sql_modules inner join sys.objects ON 
                    sys.all_sql_modules.object_id = sys.objects.object_id
                    where objectproperty(sys.all_sql_modules.object_id, 'IsProcedure') = 1 AND is_ms_shipped = 0 and uses_ansi_nulls = " +
                (ansiNullsOn ? "0" : "1") +
                "ORDER BY Name ";
    
            if (connection.State == ConnectionState.Closed)
                connection.Open();
    
            var sps = new List<SpObject>();
    
            var cmd = connection.CreateCommand();
            cmd.CommandText = sql;
    
            using (var reader = cmd.ExecuteReader())
            {
                while (reader.Read())
                {
                    sps.Add(new SpObject(reader.GetString(0), reader.GetString(1)));
                }
            }
    
            var cmdSetAnsiNulls = connection.CreateCommand();
            cmdSetAnsiNulls.CommandText = "SET ANSI_NULLS " + (ansiNullsOn ? "ON" : "OFF") + ";";
            cmdSetAnsiNulls.ExecuteNonQuery();
    
            foreach (var sp in sps)
            {
                var trans = connection.BeginTransaction();
    
                try
                {
    
                    var cmdDrop = connection.CreateCommand();
                    cmdDrop.CommandText = "DROP PROCEDURE " + sp.Name;
                    cmdDrop.Transaction = trans;
                    cmdDrop.ExecuteNonQuery();
    
    
    
                    var cmdReCreate = connection.CreateCommand();
                    cmdReCreate.CommandText = sp.Code;
                    cmdReCreate.Transaction = trans;
                    cmdReCreate.ExecuteNonQuery();
                    trans.Commit();
    
                }
                catch (Exception)
                {
                    trans.Rollback();
                    throw;
                }
            }
    
        }
    
        private class SpObject
        {
            public SpObject(string name, string code)
            {
                Name = name;
                Code = code;
            }
    
            public string Name { get; private set; }
            public string Code { get; private set; }
        }
    
    }
    

    【讨论】:

      【解决方案4】:

      到目前为止,最简单的方法是编写 s'procs 脚本,运行查找和替换命令,然后再次运行 proc 定义。

      【讨论】:

      • 当您有数百个存储过程时,这不是最简单的方法。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多