日期:2014-05-19  浏览次数:20555 次

日期运算:求插入和删除一行数据的带参存储过程
求两个带参数的存储过程,分别对下表插入一行和删除一行

交费表:jf —— 每行是一个整月的起日和止日, 该表中所有类型为'收视'的行的 止日=DATEADD(month,1, 起日) 
证号 端口 时间标记 起日 止日 类型
1 1 2009-03-10 20:19:08.577 2009.3.11 2010.4.10 收视
1 1 2009-04-10 13:21:28.507 2009.4.11 2010.5.10 收视 
1 1 2009-05-10 09:18:18.570 2009.5.11 2010.6.10 收视
1 1 2009-06-10 11:08:56.007 2009.6.11 2010.7.10 收视

所求过程细节如下:

过程1: 向该表插入一行数据: 
格式:create proc ChaRu(@证号 nvarchar(6),@端口 int,@时间标记 datetime,@起日 datetime,@止日 datetime,@类型 nvarchar(6))

过程2: 从该表删除一行数据: 
格式:create proc ShanChu(@证号 nvarchar(6),@端口 int,@起日 datetime)

对于原始表jf执行:exec ChaRu 1,1,getdate(),'2009.4.20','2009.6.3','撤线'
则jf变成下面的样子:
证号 端口 时间标记 起日 止日 状态 
1 1 2009-03-10 20:19:08.577 2009.3.11 2010.4.10 收视 --在@起日之前,保持原样 
1 1 2009-04-10 13:21:28.507 2009.4.11 2010.4.19 收视  
1 1 2009-06-12 12:32:17.055 2009.4.20 2009.6.3 撤线 --插入的新行,数据来自ChaRu的参数 
1 1 2009-04-10 13:21:28.507 2009.6.4 2009.6.24 收视 
1 1 2009-05-10 09:18:18.570 2009.6.25 2009.7.24 收视 --对原jf的2009.5.11-2009.6.10,31天变30天 
1 1 2009-06-10 11:08:56.007 2009.7.25 2009.8.24 收视 --对原jf的2009.6.11-2009.7.10,30天变31天 

上面表中两行红的相加对应原jf中的2009.4.11-2010.5.10,合计天数还是30,请注意它们的证号、端口、时间标记都相同,标志着它们原来是同一行。

ChaRu过程的规则如下:
1.jf表中被拆分的交费记录分裂成两行,这两行的合计天数应和被拆分前保持一致。 
2.jf表中,在被拆分行止日之后的各行,日期被向后顺延,但宁可改变天数,也要保持“止日=DATEADD(month,1, 起日) 
”。 

对于上面插入后的jf表执行:exec ShanChu 1,1,'2009.4.20'
则回复原状,即本帖顶部的样子。


------解决方案--------------------
1 1 2009-06-12 12:32:17.055 2009.4.20 2009.6.3 撤线 --插入的新行,数据来自ChaRu的参数 
1 1 2009-04-10 13:21:28.507 2009.6.4 2009.6.24 收视 
这条数据没看懂。尤其是2009.6.24 怎么来的。楼主可以解释下吗?

------解决方案--------------------
月份多加了一个月,改一个小地方即可。
SQL code
if object_id('[jf]') is not null drop table [jf]
go
create table [jf]([证号] int,[端口] int,[时间标记] datetime,[起日] datetime,[止日] datetime,[状态] varchar(4))
insert [jf]
select 1,1,'2009-03-10 20:19:08.577','2009.3.11','2009.4.10','收视' union all
select 1,1,'2009-04-10 13:21:28.507','2009.4.11','2009.5.10','收视' union all
select 1,1,'2009-05-10 09:18:18.570','2009.5.11','2009.6.10','收视' union all
select 1,1,'2009-06-10 11:08:56.007','2009.6.11','2009.7.10','收视'
go
--select * from [jf]

--创建存储过程:
if object_id('ChaRu','p') is not null
    drop proc ChaRu
go
create proc ChaRu(@证号 nvarchar(6),@端口 int,@时间标记 datetime,@起日 datetime,@止日 datetime,@类型 nvarchar(6))
as
    set nocount on
--所需数据插入临时表
    select 时间标记,起日,止日,状态 into #
    from jf
    where 证号=@证号 and 端口=@端口 
--获取关键的时间点
    declare @最小起日 datetime
    select @最小起日=min(起日) from jf where 止日>@起日
--插入被撤线时间截断的后一条
    insert #
    select 时间标记,@止日+1,@止日+30-datediff(d,@最小起日,@起日),状态
    from #
    where 起日=@最小起日
--更新被撤线时间截断的前一条
    update #
    set 止日=@起日-1
    where 起日=@最小起日
--插入撤线记录
    insert # values(@时间标记,@起日,@止日,'撤线')
--将撤线止日之后的日期顺延
    update # 
    set 起日=dateadd(m,datediff(m,@最小起日,#.起日)-1,@止日+31-datediff(d,@最小起日,@起日))
        ,止日=dateadd(m,datediff(m,@最小起日,#.起日),@止日+30-datediff(d,@最小起日,@起日))
    from jf t
    where #.起日=t.起日 and t.证号=@证号 and t.端口=@端口 and t.起日>@最小起日
--删除已有记录
    delete jf where 证号=@证号 and 端口=@端口 
--插入新整合的记录
    insert jf 
    select @证号,@端口,时间标记,起日,止日,状态 from # order by 起日
go

--测试结果:
exec ChaRu 1,1,'2009-06-12 12:32:17.055','2009.4.20','2009.6.3','撤线' 
select * from [jf]
/*
证号          端口          时间标记                    起日                      止日                      状态
----------- ----------- ----------------------- -------