【问题标题】:tsql dynamic table stored proceduretsql动态表存储过程
【发布时间】:2015-12-21 07:07:36
【问题描述】:

我写了一个长长的存储过程列表来更新一些表,完成后我意识到大部分存储过程彼此非常相似......只有少数字段发生变化

然后我想创建一个存储过程,这就是我所做的:

CREATE PROCEDURE dbo.Save_All
(
    @UID            nvarchar(100)   = NULL,  --All
    @Table          nvarchar(40)    = NULL, --All
    @ID             int             = 0,        --All
    ...
    @SubCategory    nvarchar(50)    = NULL, --              Ticker
    @Link           nvarchar(300)   = NULL  --              Ticker
)
AS
    SET NOCOUNT ON;
BEGIN
    DECLARE @S      nvarchar(max)='',
            @P      nvarchar(max)='',
            @cols1  nvarchar(max)='',
            @cols2  nvarchar(max)='',
            @cols3  nvarchar(max)=''

    SELECT @cols1= ISNULL(@cols1 + ',','') + QUOTENAME(name) 
        FROM (SELECT top (100) name  FROM sys.columns  
        WHERE id=OBJECT_ID(@Table) and name<>'ID' Order by colID) AS Columns; 
    SELECT @cols2= ISNULL(@cols2 + ',','') + '@_' + name 
        FROM (SELECT top (100) name  FROM sys.columns  
        WHERE id=OBJECT_ID(@Table) and name<>'ID' Order by colID) AS Columns; 
    SELECT @cols3= ISNULL(@cols3 + ',','') + QUOTENAME(name)+'=@_'+ name   
        FROM (SELECT top (100) name  FROM sys.columns  
        WHERE id=OBJECT_ID(@Table) and name<>'ID' Order by colID) AS Columns; 

    SELECT @cols1 = STUFF(@cols1, 1, 1, '');
    SELECT @cols2 = STUFF(@cols2, 1, 1, '');
    SELECT @cols3 = STUFF(@cols3, 1, 1, '');

    IF (@ID=0 OR @ID is null) 
        SET @S = N'INSERT INTO @_Table ('+ @cols1 + ') VALUES ('+@cols2+')' 
    ELSE
        SET @S = N' UPDATE @_Table SET ' +@cols3 +' WHERE ID=@_ID' 

    --PRINT @S

    SET @P=  '@_UID                 nvarchar(100),
              @_Table               nvarchar(40),
              @_ID                  int,
              ...
              @_SubCategory         nvarchar(50),
              @_Link                nvarchar(300)'

    EXEC sp_executesql @S,@P,@UID,@Table,@ID,...,@SubCategory,@Link
END
SET NOCOUNT OFF

但是,虽然参数列表很长(我在示例中修改了大部分参数),但它并没有包括所有表的所有字段,因此在很多情况下都会返回错误..

解决方案是在@cols1/2/3 中仅包含定义为参数的字段.. 或将相对@_xx 设置为空

但这超出了我目前的知识范围..

顺便说一句.. 存储过程呢?它包含哪些不可接受的错误?

谢谢! 乔

【问题讨论】:

  • 您应该为您的存储过程使用sp_ 前缀。微软有reserved that prefix for its own use (see Naming Stored Procedures),你确实会在未来某个时候冒着名称冲突的风险。 It's also bad for your stored procedure performance。最好只是简单地避免 sp_ 并使用其他东西作为前缀 - 或者根本不使用前缀!
  • 此外,从 SQL Server 2005 起,建议使用 sys 架构中的系统目录视图 - 例如sys.columns - 而不是旧的、即将被弃用的 syscolumns 视图。
  • 好的,注意了..我立即修改
  • 我看不到你在哪里更新@_ID?这没有意义 WHERE ID=@_ID 如果@_ID 始终为 0 还是我错了?
  • @ID是输入参数,即标识列:如果为0则插入,因为不存在0列,如果大于0则升级

标签: sql-server tsql stored-procedures dynamic


【解决方案1】:

嗯,我找到了解决方案,而且比想象的要容易..

感动 @P 定义在上面并添加

SET @P= '...'

在顶部并添加

AND CHARINDEX('@_'+name+' ',@P)>0 

到规则创建3

@cols

大家一起:

CREATE PROCEDURE dbo.Save_All
(
@UID            nvarchar(100)   = NULL, --All
@Table          nvarchar(40)    = NULL, --All
@ID             int             = 0,    --All
...
@SubCategory    nvarchar(50)    = NULL, --              Ticker
@Link           nvarchar(300)   = NULL  --              Ticker
)
AS
SET NOCOUNT ON;
BEGIN
    DECLARE @S      nvarchar(max)='',
            @P      nvarchar(max)='',
            @cols1  nvarchar(max)='',
            @cols2  nvarchar(max)='',
            @cols3  nvarchar(max)=''

    SET @P=  '@_UID                 nvarchar(100),
              @_Table               nvarchar(40),
              @_ID                  int,
              ...
              @_SubCategory         nvarchar(50),
              @_Link                nvarchar(300)'

    SELECT @cols1= ISNULL(@cols1 + ',','') + QUOTENAME(name) 
        FROM (SELECT top (100) name  FROM sys.columns  
        WHERE id=OBJECT_ID(@Table) and name<>'ID' 
        AND CHARINDEX('@_'+name+' ',@P)>0 Order by colID) AS Columns; 
    SELECT @cols2= ISNULL(@cols2 + ',','') + '@_' + name 
        FROM (SELECT top (100) name  FROM sys.columns  
        WHERE id=OBJECT_ID(@Table) and name<>'ID' 
        AND CHARINDEX('@_'+name+' ',@P)>0Order by colID) AS Columns; 
    SELECT @cols3= ISNULL(@cols3 + ',','') + QUOTENAME(name)+'=@_'+ name   
        FROM (SELECT top (100) name  FROM sys.columns  
        WHERE id=OBJECT_ID(@Table) and name<>'ID' 
        AND CHARINDEX('@_'+name+' ',@P)>0Order by colID) AS Columns; 

    SELECT @cols1 = STUFF(@cols1, 1, 1, '');
    SELECT @cols2 = STUFF(@cols2, 1, 1, '');
    SELECT @cols3 = STUFF(@cols3, 1, 1, '');

    IF (@ID=0 OR @ID is null) 
        SET @S = N'INSERT INTO @_Table ('+ @cols1 + ') VALUES ('+@cols2+')' 
    ELSE
        SET @S = N' UPDATE @_Table SET ' +@cols3 +' WHERE ID=@_ID' 

    --PRINT @S

    EXEC sp_executesql @S,@P,@UID,@Table,@ID,...,@SubCategory,@Link
END
SET NOCOUNT OFF

嗯,有点粗糙..肯定有更好的方法来构建它,但到目前为止..似乎效果很好

感谢大家阅读! 乔

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-12
    • 1970-01-01
    • 1970-01-01
    • 2015-03-10
    • 1970-01-01
    相关资源
    最近更新 更多