Tsql 创建可以使用不同表的存储过程

Tsql 创建可以使用不同表的存储过程,tsql,stored-procedures,view,Tsql,Stored Procedures,View,我需要对数据库中具有相同结构的许多表使用相同的存储过程。这是从客户处加载的数据,有一个表/客户,数据需要在加载到数据仓库之前运行计算/检查 到目前为止,这些是我发现的选项和问题,我正在寻找更好的模式/方法 创建一个指向对象的视图 我要处理的表,SPs 然后谈谈这个观点。这很有效 嗯(尤其是我锻炼过之后) 如何“自动”创建视图 基于其列)。但是 视图只能与一个表一起使用 一次,强制系统 一次处理一个客户 在每个SP中使用动态sql- 使SPs更难操作 读取/调试,由于这些原因 被排除在外 跨多个视

我需要对数据库中具有相同结构的许多表使用相同的存储过程。这是从客户处加载的数据,有一个表/客户,数据需要在加载到数据仓库之前运行计算/检查

到目前为止,这些是我发现的选项和问题,我正在寻找更好的模式/方法

  • 创建一个指向对象的视图 我要处理的表,SPs 然后谈谈这个观点。这很有效 嗯(尤其是我锻炼过之后) 如何“自动”创建视图 基于其列)。但是 视图只能与一个表一起使用 一次,强制系统 一次处理一个客户

  • 在每个SP中使用动态sql- 使SPs更难操作 读取/调试,由于这些原因 被排除在外

  • 跨多个视图创建分区视图 所有表格,然后使用 要返回的参数化表函数 只是我们感兴趣的数据- 啊,但是我不能更新数据 函数返回一个 只能用于选择

  • 在函数中使用动态sql (无法完成)以创建视图 (这也是做不到的)。。。。给 向上
  • 在SP中创建临时表 在目标表上使用 动态sql,然后是临时表 仅存在于运行的会话中 动态sql不是“父级” 正在运行SP的会话。。。 放弃
  • 使用创建全局临时表 动态SQL以避免范围问题 设置为5,然后针对 全局临时表。还碰到 单一客户问题
  • 在视图中创建视图,如图1所示 事务,然后运行所有SP 然后提交-对一个人来说很好 用户,但任何其他用户现在都被阻止 正在尝试创建的新视图 同名
  • 使用临时视图。。。不能进来 T/Sql
  • 将所有代码移到.Net中-但是 我们在哪里有环境问题 tsql更易于托管/运行

  • 我知道我不是唯一一个有这个问题的人,你们当中有谁解决了这个问题,请帮忙

    我相当肯定,解决这个问题的标准方法是在每个sp(您的选项2)中使用动态SQL,这已经被排除了


    您的目标是生成通用的多表SQL。我看不出您打算如何在不牺牲一些效率和可读性的情况下实现这一点

    也许你的方法是错误的,我将在一段时间内深入讨论细节,但似乎你的问题可以通过SSIS解决

    --更新的答案

    首先,大局:

    动态处理表的最经济的方法是使用脚本而不是存储过程。如果希望随机选择表访问,则肯定不会使用存储过程的任何性能优势,即执行计划。SQL脚本可以在运行时使用占位符轻松升级为指向一个表,并在执行之前替换它

    可以从文件系统、变量、表中的文本列等加载脚本。加载过程包括将脚本内容读取到字符串变量。此步骤只发生一次

    下一步是准备阶段。将对要处理的每个表执行此步骤。此步骤的主要业务是用正在处理的当前表替换表占位符。还可以设置参数值,就像您需要传递到已编写的sp中的任何参数一样

    最后一步是脚本的执行。由于已加载到变量中,且占位符已设置为当前表名,因此可以安全地使用sql变量作为输入调用ExecuteSQLSTASK。当然,对于要处理的每个表,都会发生此过程

    嗯。现在让我们看看这一点的实际效果

    这是一个示例数据库模型:

    CREATE TABLE [dbo].[t_n](
      [id] [int] IDENTITY(1,1) NOT NULL,
      [name] [varchar](50) NOT NULL,
      [start] [datetime] NULL,
      CONSTRAINT [PK_t_n] PRIMARY KEY CLUSTERED ([id] ASC)
    ) ON [PRIMARY]
    
    其中t_n表示任何表(t_1、t_2、t_3等)

    这是您当前的存储过程:

    CREATE PROCEDURE SpProcessT_n 
    AS
    BEGIN
        SET NOCOUNT ON;
        SELECT * FROM [t1]; 
    END
    GO
    
    现在,将此存储过程转换为Sql脚本,放置占位符而不是表名

        SET NOCOUNT ON;
        SELECT * FROM [$table_name];
    
    我选择将其保存在文件系统中的.sql文件中,以使POC尽可能简单

    接下来,创建一个SSIS包,如下所示:

    以下是我选择用来设置循环的设置:

    这是一种将表名分配给变量的方法,该变量被适当地称为_table_name_

    这是脚本任务的设置,您会发现变量_table_name_uu具有只读访问权限,而名为SqlExec的新变量具有读/写访问权限:

    这是它的主要功能:

        public void Main()
        {
            String Table_Name = Dts.Variables["table_name"].Value.ToString();
            String SqlScript;
            Regex reg = new Regex(@"\$table_name", RegexOptions.Compiled);
            using (var f = File.OpenText(@"c:\sqlscript.sql")) {
                SqlScript = f.ReadToEnd();
                f.Close();
            }
            SqlScript = reg.Replace(SqlScript, Table_Name);
            Dts.Variables["SqlExec"].Value = SqlScript;
            Dts.TaskResult = (int)ScriptResults.Success;
        }
    
    您可以注意到Dts变量SqlExec包含将要执行的sql脚本。现在,您可以在ExecuteSqlTask中设置以下选项:

    在MSSQL 2008中成功测试,如果在脚本文件中插入一个insert,您将注意到每个表中都有新行


    希望这有帮助

    是否编写包含表名的分区视图

    SELECT 'TableName', t.* FROM TableName t
    UNION ALL 
    SELECT 'TableName2', t.* FROM TableName2 t
    

    然后编写一个使用动态SQL进行编写的单一而非触发器(使用动态SQL所涉及的测试较少,因为我认为您只需为所有表编写一次简单的CRUD操作)

    如果您的应用程序可以延迟一天截止,然后,您可以安排一个夜间作业来运行SSIS包,该包将所有150多个表合并到一个巨大的表中。由于针对该巨大表的查询结果的新鲜度将延迟1个“日期”,因此该解决方案将不包括最近加载的任何行

    实际上,您可以计时此包的运行。如果它仍然惊人地快,比如说在30分钟内,那么你可以打赌每隔几个小时运行一次,比如:工作日开始、午餐休息和一天结束。这样,您就可以有一个几乎全新的数据来查询w