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

你认为似乎是什么问题?这样做的正确方法是什么?

4

4 回答 4

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
于 2012-04-11T13:26:24.160 回答
0

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

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

于 2012-04-11T13:22:10.970 回答
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需要更新的每个字段。

于 2012-04-11T13:28:15.637 回答
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 之前,一定要阅读并理解优秀的文章动态 SQL 的诅咒和祝福!

于 2012-04-11T13:29:20.097 回答