确定动态列以在存储过程中更新

时间:2012-04-11 13:16:43

标签: sql-server stored-procedures dynamic

我想在运行时动态确定要在存储过程中更新哪一列

我有一张表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

您认为似乎是什么问题?什么是正确的方法呢?

4 个答案:

答案 0 :(得分: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

答案 1 :(得分:0)

SQL CASE语句仅对字段值进行操作,而不对表字段名称进行操作。

顺便说一句,如果您可以选择删除JanDone,FebDone等字段并映射到引用表,我强烈建议您更改数据库架构。

答案 2 :(得分: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

答案 3 :(得分: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