标签:sql cursor
好久没有写SQL CURSOR了,语法的有点生疏了。今天写了个玩玩。呵呵!该功能是计算客户的丢失和恢复分析信息的。
/* Definition: Customer had sales before, but there is no sales in the last six month. e.g: Before or in June has sales From July to Dec – no sales Customer lost in Jan */ /* Following is the Solution: */ /* Create a new CUSTOMER_STATUS to save the analysis data USE [DW] GO SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO CREATE TABLE [dbo].[CUSTOMER_STATUS]( [CUSTOMER_NAME] [nchar](100) NOT NULL, [CUSTOMER_ID] [int] NOT NULL, [YEAR] [nchar](4) NOT NULL, [MONTH] [nchar](2) NOT NULL, [STATUS] [nchar](20) NOT NULL, [INVOICE_DATE] [date] NOT NULL ) ON [PRIMARY] GO ALTER TABLE [dbo].[CUSTOMER_STATUS] ADD CONSTRAINT [DF_CUSTOMER_STATUS_YEAR] DEFAULT ('') FOR [YEAR] GO ALTER TABLE [dbo].[CUSTOMER_STATUS] ADD CONSTRAINT [DF_CUSTOMER_STATUS_MONTH] DEFAULT ('') FOR [MONTH] GO */ --Use the Cursor to get the target data use DW --测试的时候需要把表里的数据删除了 truncate table CUSTOMER_STATUS declare @CUSTOMER_ID int declare @CUSTOMER_NAME char(100) declare @INVOICE_DATE date --记录游标里的下一条记录 declare @CUSTOMER_ID_NEXT int declare @CUSTOMER_NAME_NEXT char(100) declare @INVOICE_DATE_NEXT date --记录丢失客户的那个的月份 declare @INVOICE_DATE_LOST date --记录循环次数 declare @LOOP_COUNT INT SET @LOOP_COUNT=0 declare @sql char(5000) declare table_customer_cursor cursor for select c.[CUSTOMER_ID],c.CUSTOMER_NAME,h.[INVOICE_DATE] --COUNT(*) TransTimes from [dbo].[VSC_BI_CUSTOMER] c,[dbo].[VSC_BI_INV_HEADERS] h where c.[CUSTOMER_ID]=h.[CUSTOMER_ID] and h.[INVOICE_DATE]>'2012-03-31' group by c.[CUSTOMER_ID],c.CUSTOMER_NAME,h.[INVOICE_DATE] --having count(*)>=1 order by c.[CUSTOMER_ID],c.CUSTOMER_NAME,h.[INVOICE_DATE] open table_customer_cursor fetch next from table_customer_cursor into @CUSTOMER_ID,@CUSTOMER_NAME,@INVOICE_DATE WHILE @@FETCH_STATUS = 0 BEGIN --第一进入循环的时候,@CUSTOMER_ID_NEXT是空的,这个时候直接用上面这个语句取到的值fetch next from table_customer_cursor into @CUSTOMER_ID,@CUSTOMER_NAME,@INVOICE_DATE if @CUSTOMER_ID_NEXT<>'' BEGIN set @CUSTOMER_ID=@CUSTOMER_ID_NEXT set @CUSTOMER_NAME = @CUSTOMER_NAME_NEXT set @INVOICE_DATE = @INVOICE_DATE_NEXT END SET @LOOP_COUNT=@LOOP_COUNT+1 print @LOOP_COUNT --第一条记录插入到[dbo].[CUSTOMER_STATUS]表里,而且STATUS=NEW IF @LOOP_COUNT=1 BEGIN --set @sql='insert into CUSTOMER_STATUS(CUSTOMER_ID,CUSTOMER_NAME,STATUS,INVOICE_DATE) values('+@CUSTOMER_ID+','+''''+@CUSTOMER_NAME+''''+','+'NEW'+','+@INVOICE_DATE+')' --print @sql --exec(@sql) insert into CUSTOMER_STATUS(CUSTOMER_ID,CUSTOMER_NAME,STATUS,INVOICE_DATE)values(+@CUSTOMER_ID,@CUSTOMER_NAME,'NEW',@INVOICE_DATE) END ELSE --不是一个客户的第一条记录 --set @sql='delete from '+@tblname --exec(@sql) print @CUSTOMER_ID print @CUSTOMER_NAME print @INVOICE_DATE fetch next from table_customer_cursor into @CUSTOMER_ID_NEXT,@CUSTOMER_NAME_NEXT,@INVOICE_DATE_NEXT --set @CUSTOMER_ID_NEXT = @CUSTOMER_ID --set @CUSTOMER_NAME_NEXT = @CUSTOMER_NAME --set @INVOICE_DATE_NEXT = @INVOICE_DATE print '显示下一行的记录 ' print @CUSTOMER_ID_NEXT print @CUSTOMER_NAME_NEXT print @INVOICE_DATE_NEXT --计算逻辑如下: --如果相邻的两条记录是一个相同的客户,则需要比较两条记录的时间间隔, --1,如果时间间隔大于6个月,则表示这个客户在上一个时间的基础上加6个月份丢失的,这个时候需要把该客户在那个丢失的月份插入到CUSTOMER_STATUS表里 --同时还要把此期间的下区间记录插入到CUSTOMER_STATUS表,表示此客户在此条记录的月份RECOVERY --2, 如果时间间隔小于6个月在插入此记录到CUSTOMER_STATUS表里,同时STATUS是NORMAL --总上所述,除了需要把循环的表记录都要插入CUSTOMER_STATUS表里外,还要插入丢失的那个月份的信息 --如果一个客户循环到最后一条记录,此时要判断该记录距离getdate的时间是否大于6个月,如果是则是丢失LOST(这个时候需要再插入一条丢失的记录, --即最后一次交易的时间加6个月),否则是正常NORMAL --Notes:如果客户只有一次交易,则需要特别的考虑,这个时候需要插入两条记录,一条是NEW,一条是丢失的记录 IF (@CUSTOMER_ID=@CUSTOMER_ID_NEXT and @CUSTOMER_NAME=@CUSTOMER_NAME_NEXT) --表示还是同一个客户 --BEGIN --@INVOICE_DATE_NEXT-@INVOICE_DATE>180 if DATEDIFF(day,@INVOICE_DATE,@INVOICE_DATE_NEXT)>180 begin --set @INVOICE_DATE_LOST=@INVOICE_DATE+180 set @INVOICE_DATE_LOST=dateadd(day,180,@INVOICE_DATE) --插入客户丢失的月份信息 insert into CUSTOMER_STATUS(CUSTOMER_ID,CUSTOMER_NAME,STATUS,INVOICE_DATE)values(+@CUSTOMER_ID_NEXT,@CUSTOMER_NAME_NEXT,'LOST',@INVOICE_DATE_LOST) --插入恢复的月份信息 insert into CUSTOMER_STATUS(CUSTOMER_ID,CUSTOMER_NAME,STATUS,INVOICE_DATE)values(+@CUSTOMER_ID_NEXT,@CUSTOMER_NAME_NEXT,'RECOVERY',@INVOICE_DATE_NEXT) end else insert into CUSTOMER_STATUS(CUSTOMER_ID,CUSTOMER_NAME,STATUS,INVOICE_DATE)values(+@CUSTOMER_ID_NEXT,@CUSTOMER_NAME_NEXT,'NORMAL',@INVOICE_DATE_NEXT) ELSE --不是同一个客户 BEGIN SET @LOOP_COUNT=0 --是为了把每个客户的第一次交易时,他们会是我们的新客 --此时客户循环到最后一条记录,此时要判断该记录距离getdate的时间是否大于6个月,如果是则是丢失LOST(这个时候需要再插入一条丢失的记录, --即最后一次交易的时间加6个月),否则是正常NORMAL if DATEDIFF(day,@INVOICE_DATE,getdate())>180 BEGIN insert into CUSTOMER_STATUS(CUSTOMER_ID,CUSTOMER_NAME,STATUS,INVOICE_DATE)values(+@CUSTOMER_ID,@CUSTOMER_NAME,'LOST',dateadd(day,180,@INVOICE_DATE)) --update CUSTOMER_STATUS set STATUS='LOST' where CUSTOMER_ID=@CUSTOMER_ID and CUSTOMER_NAME=@CUSTOMER_NAME and INVOICE_DATE=dateadd(day,180,@INVOICE_DATE) END END END close table_customer_cursor deallocate table_customer_cursor --更新下YEAR和MONTH,其实BI里可以直接用INOVICE_DATE就可以关联到YEAR,MONTH,QUARTER您自己看吧,需要就加上。 update CUSTOMER_STATUS set YEAR=YEAR(INVOICE_DATE),MONTH=MONTH(INVOICE_DATE) /* 验证用的SQL truncate table CUSTOMER_STATUS select * from CUSTOMER_STATUS where 1=1 --AND status='RECOVERY' AND CUSTOMER_ID=3698 order by customEr_id ,invoice_date */
标签:sql cursor
原文地址:http://blog.csdn.net/waterxcfg304/article/details/42985963