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を使用してこれを実現できます。基本的には、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 に答える
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 に答える