如何避免SQL WHILE循环中执行INSERT的重复CASE语句

时间:2013-10-27 11:54:39

标签: sql sql-server tsql

有没有办法简化此脚本,以便CASE语句不重复?在这个缩短的例子中它看起来可以接受,但实际上CASE语句要长得多,因为我有“每2周”,每4周一次“,”每月“等等。我正在使用SQL Server和WHILE声明来表现理由:CTE或MERGE会帮忙吗?

        DECLARE @theStartDate DATE
DECLARE @Interval INT
DECLARE @eventCharges TABLE
(
    [EventDate] [datetime],
    Person_Id int
)

SET @today = GETDATE()
SET @Interval = 0

-- delete event charges from previous user  
DELETE FROM @eventCharges

-- Insert the calculated transactions   
WHILE @Interval < 100
BEGIN
SET @Interval = @Interval + 1
INSERT INTO @eventCharges
SELECT
    CASE
        WHEN pcc.Recurrence = 'Daily' 
        THEN DATEADD(DAY, @Interval, @theStartDate)
        WHEN pcc.Recurrence = 'Weekly'
        THEN DATEADD(WEEK, @Interval, @theStartDate)            
    END AS EventDate
    ,pcc.Person_Id
FROM @personChargeCurrent pcc   
WHERE CASE
            WHEN pcc.Recurrence = 'Daily' 
            THEN DATEADD(DAY, @Interval, @theStartDate)
            WHEN pcc.Recurrence = 'Weekly'
            THEN DATEADD(WEEK, @Interval, @theStartDate)
        END <= @today
    AND NOT EXISTS(SELECT 1 FROM dbo.PersonChargeTransaction pct 
                    WHERE pct.Person_Id = pcc.Person_Id
                    AND pct.PersonCharge_Id = pcc.Id
                    AND pct.TransactionDate = 
                    CASE
                        WHEN pcc.Recurrence = 'Daily' 
                        THEN DATEADD(DAY, @Interval, @theStartDate)
                        WHEN pcc.Recurrence = 'Weekly'
                        THEN DATEADD(WEEK, @Interval, @theStartDate)
                    END)
ORDER BY StartDate
END

3 个答案:

答案 0 :(得分:2)

您可以将其包装在一个函数中:

Create Function dbo.IntervalEnd(
    @recurrence varchar(10),
    @interval int,
    @startDate date -- or whatever data type you're using for dates
) returns date as
begin
    return case
        when @recurrence = 'Daily' then dateadd(day, @interval, @startDate)
        when @recurrence = 'Weekly' then dateadd(week, @interval, @startDate)
    end
end

然后

Insert Into @eventCharges
Select
    dbo.IntervalEnd(pcc.Recurrence, @Interval, @theStartDate) as EventDate,
    pcc.Person_Id
From
    @personChargeCurrent pcc   
Where
    dbo.IntervalEnd(pcc.Recurrence, @Interval, @theStartDate) <= @today And
    Not Exists (
        Select
            1
        From
            dbo.PersonChargeTransaction pct 
        Where
            pct.Person_Id = pcc.Person_Id And
            pct.PersonCharge_Id = pcc.Id And
            pct.TransactionDate 
                = dbo.IntervalEnd(pcc.Recurrence, @Interval, @theStartDate)
    )

使用函数有开销。你必须决定稍微降低的性能是否值得权衡,以提高可读性。

答案 1 :(得分:1)

是的,CTE应该有所帮助。尝试将INSERT语句更改为:

WITH cte as 
(SELECT CASE
            WHEN Recurrence = 'Daily' 
            THEN DATEADD(DAY, @Interval, @theStartDate)
            WHEN Recurrence = 'Weekly'
            THEN DATEADD(WEEK, @Interval, @theStartDate)            
        END AS EventDate,
        p.*
 FROM @personChargeCurrent p)
INSERT INTO @eventCharges
SELECT cte.EventDate, cte.Person_Id
FROM cte
WHERE cte.EventDate <= @today AND 
      NOT EXISTS
      (SELECT 1 
       FROM dbo.PersonChargeTransaction pct 
       WHERE pct.Person_Id = cte.Person_Id AND 
             pct.PersonCharge_Id = cte.Id AND 
             pct.TransactionDate = cte.EventDate)
ORDER BY StartDate

答案 2 :(得分:0)

您可以创建一个临时表,在其中插入计算字段,然后将该表与连接一起使用以插入数据/应用条件