2012-04-11 19 views
1

更新我希望在运行时其列在存储过程中更新动态确定动态确定列在存储过程中

我有一个表BshForecast有类似的属性:

projectId, JobTypeId, Year, JanDone, FebDone, MarDone... (for all months) 

而且我有此存储过程不起作用

CREATE PROCEDURE [dbo].[SP_Update_Done_Last_Month2] 
    @Project_ID INT, 
    @Job_Type_ID INT 
AS 
BEGIN 
    SET NOCOUNT ON; 

    DECLARE @LAST_MONTH INT 
    SET @LAST_MONTH = DATEPART(MM,DATEADD(MM, -1, GETDATE())) 

    UPDATE BshForecast 
    Set (CASE @LAST_MONTH 
      WHEN 1  THEN JanDone  
      WHEN 2  THEN FebDone  
      WHEN 3  THEN MarDone 
      WHEN 4  THEN AprDone 
      WHEN 5  THEN MayDone 
      WHEN 6  THEN JunDone 
      WHEN 7  THEN JulDone 
      WHEN 8  THEN AugDone 
      WHEN 9  THEN SepDone 
      WHEN 10 THEN OctDone 
      WHEN 11 THEN NovDone 
      WHEN 12 THEN DecDone 
      END) = 0 
    WHERE 
     (ProjectId = @Project_ID) 
     and (JobTypeId = @Job_Type_ID) 
     and (Year = DATEPART(YY, DATEADD(MM, -1, GETDATE()))) 
END 

您认为似乎是什么问题?什么是正确的方法来做到这一点?

+0

问题是:SQL Server的'CASE'语句可以提供**值** - 但不包括SQL语句的部分(如列名).....您不能动态地选择要更新的列。还有:你自己的存储过程应该不使用'sp_'前缀 - 它由Microsoft保留用于自己的使用。 – 2012-04-11 13:21:09

+0

PS:它是**预测**(在中间有一个“e”) - 不是*预测*因为您拥有它... – 2012-04-11 13:21:27

回答

0

SQL CASE语句只对字段值操作,而不对表字段名称操作。另外,我强烈建议您改变数据库模式,如果您有选择摆脱JanDone,FebDone等字段并映射到参考表,请改为。

3

尝试用这个替换您的SET条款:

SET 
    JanDone = case when @LAST_MONTH = 1 then 0 else JanDone end, 
    FebDone = case when @LAST_MONTH = 2 then 0 else FebDone end, 
    MarDone = case when @LAST_MONTH = 3 then 0 else MarDone end, 
    AprDone = case when @LAST_MONTH = 4 then 0 else AprDone end, 
    MayDone = case when @LAST_MONTH = 5 then 0 else MayDone end, 
    JunDone = case when @LAST_MONTH = 6 then 0 else JunDone end, 
    JulDone = case when @LAST_MONTH = 7 then 0 else JulDone end, 
    AugDone = case when @LAST_MONTH = 8 then 0 else AugDone end, 
    SepDone = case when @LAST_MONTH = 9 then 0 else SepDone end, 
    OctDone = case when @LAST_MONTH = 10 then 0 else OctDone end, 
    NovDone = case when @LAST_MONTH = 11 then 0 else NovDone end, 
    DecDone = case when @LAST_MONTH = 12 then 0 else DecDone end 
+0

也请查看CASE的文档: http:// msdn.microsoft.com/en-us/library/ms181765.aspx – GolfWolf 2012-04-11 13:51:46

0

你可以扩充现有的查询,使之准确:

Set JanDone = (CASE WHEN @LAST_MONTH = 1 THEN 0 ELSE JanDone END), 
    FebDone = (CASE WHEN @LAST_MONTH = 2 THEN 0 ELSE FebDone END), 
    ... 

你只需要一个CASE每次你需要更新字段。

0

您可以使用动态SQL来实现此目的 - 基本上在构建SQL语句“实时”并在存储过程中执行它。

事情是这样的:

CREATE PROCEDURE [dbo].[proc_Update_Done_Last_Month2] 
    @Project_ID INT, 
    @Job_Type_ID INT 
AS 
BEGIN 
    SET NOCOUNT ON; 

    DECLARE @LAST_MONTH INT 
    SET @LAST_MONTH = DATEPART(MM,DATEADD(MM, -1, GETDATE())) 

    DECLARE @SqlStmt NVARCHAR(MAX) 

    SET @SqlStmt = N'UPDATE BshForecast SET ' + 
     CASE @LAST_MONTH 
      WHEN 1  THEN N'JanDone' 
      WHEN 2  THEN N'FebDone'  
      WHEN 3  THEN N'MarDone' 
      WHEN 4  THEN N'AprDone' 
      WHEN 5  THEN N'MayDone' 
      WHEN 6  THEN N'JunDone' 
      WHEN 7  THEN N'JulDone' 
      WHEN 8  THEN N'AugDone' 
      WHEN 9  THEN N'SepDone' 
      WHEN 10 THEN N'OctDone' 
      WHEN 11 THEN N'NovDone' 
      WHEN 12 THEN N'DecDone' 
     END + N' = 0 WHERE ProjectId = @Project_ID AND JobTypeId = @Job_Type_ID AND Year = DATEPART(YY, DATEADD(MM, -1, GETDATE()))' 

    PRINT @SqlStmt   

    EXEC sp_executesql @SqlStmt 
END 

动态SQL有它的困难和问题 - 一定要读取并开始使用动态SQL在您的项目之前,了解的优秀文章The curse and blessings of dynamic SQL