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 @[email protected]_ID_NEXT
			set @CUSTOMER_NAME = @CUSTOMER_NAME_NEXT
			set @INVOICE_DATE = @INVOICE_DATE_NEXT
		END

	SET @[email protected]_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('[email protected]_ID+','+''''[email protected]_NAME+''''+','+'NEW'+','[email protected]_DATE+')'
			--print @sql
			--exec(@sql)
			insert into CUSTOMER_STATUS(CUSTOMER_ID,CUSTOMER_NAME,STATUS,INVOICE_DATE)values([email protected]_ID,@CUSTOMER_NAME,'NEW',@INVOICE_DATE)
		END
	ELSE --不是一个客户的第一条记录
		--set @sql='delete from  '[email protected]
		--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 (@[email protected]_ID_NEXT and @[email protected]_NAME_NEXT)  --表示还是同一个客户
			--BEGIN
				[email protected][email protected]_DATE>180
				if DATEDIFF(day,@INVOICE_DATE,@INVOICE_DATE_NEXT)>180
					begin
						--set @[email protected]_DATE+180
						set @INVOICE_DATE_LOST=dateadd(day,180,@INVOICE_DATE)
						--插入客户丢失的月份信息
						insert into CUSTOMER_STATUS(CUSTOMER_ID,CUSTOMER_NAME,STATUS,INVOICE_DATE)values([email protected]_ID_NEXT,@CUSTOMER_NAME_NEXT,'LOST',@INVOICE_DATE_LOST)
						--插入恢复的月份信息
						insert into CUSTOMER_STATUS(CUSTOMER_ID,CUSTOMER_NAME,STATUS,INVOICE_DATE)values([email protected]_ID_NEXT,@CUSTOMER_NAME_NEXT,'RECOVERY',@INVOICE_DATE_NEXT)
					end
				else
					insert into CUSTOMER_STATUS(CUSTOMER_ID,CUSTOMER_NAME,STATUS,INVOICE_DATE)values([email protected]_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([email protected]_ID,@CUSTOMER_NAME,'LOST',dateadd(day,180,@INVOICE_DATE))
						--update CUSTOMER_STATUS set STATUS='LOST' where [email protected]_ID and [email protected]_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
*/

时间: 2024-11-06 21:17:18

SQL CURSOR的相关文章

SQL Cursor 游标的使用

Contents SQL Cursor 游标的使用 这两天在做新老系统间的data migration,接触到sql的游标,记录总结一下. 我们的需求是要求map多张表,并把计算结果分别更新到一张目标表中, 新旧系统要做A/B Testing, 所以当旧表有任何更新,比如新增,删除,改动, 都要更新到新表中. 原本我选择的方案是采用批量Insert, 但碰到一个需要插入map关系的表, 其中一个field是另外一张表刚刚插入数据的id, 因此只能用循环来解决. 看了一圈SQL的for循环,实现起

SQL Cursor 基本用法

Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/--> 1 table1结构如下 id int name varchar(50) declare @id int declare @name varchar(50) declare cursor1 cursor for --定义游标cursor1 select * from table1 --使用游标的对象(

sql Cursor的用法

table1结构如下 2 id int 3 name varchar(50) 4 5 declare @id int 6 declare @name varchar(50) 7 declare cursor1 cursor for --定义游标cursor1 8 select * from table1 --使用游标的对象(跟据需要填入select文) 9 open cursor1 --打开游标 10 11 fetch next from cursor1 into @id,@name --将游标

SQL Cursor 基本用法[用两次FETCH NEXT FROM INTO语句?]

Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/--> 1 table1结构如下 id int name varchar(50) declare @id int declare @name varchar(50) declare cursor1 cursor for --定义游标cursor1 select * from table1 --使用游标的对象(

游标SQL Cursor 基本用法

http://www.cnblogs.com/Gavinzhao/archive/2010/07/14/1777644.html 1 table1结构如下 2 id    int 3 name  varchar(50) 4  5 declare @id int 6 declare @name varchar(50) 7 declare cursor1 cursor for         --定义游标cursor1 8 select * from table1               --使

SQL Cursor(游标)

1.游标在数据表没有id(identity(1,1))时好用,但是游标会吃更多的内存,减少可用的并发,占用宽带,锁定资源,当然还有更多的代码量 2.如果能不用游标,尽量不要使用游标,用完用完之后一定要关闭和释放, 尽量不要在大量数据上定义游标,尽量不要使用游标上更新数据 Cursor:Global for--全局游标 Cursor:Local for--局部游标 LOCAL意味着游标的生存周期只在批处理或函数或存储过程中可见 GLOBAL意味着游标对于特定连接作为上下文,全局内有效 --第一步:

PyMySQL防止SQL注入

一.SQL注入简介 SQL注入是比较常见的网络攻击方式之一,它不是利用操作系统的BUG来实现攻击,而是针对程序员编程时的疏忽,通过SQL语句,实现无帐号登录,甚至篡改数据库. 二.SQL注入攻击的总体思路 1.寻找到SQL注入的位置 2.判断服务器类型和后台数据库类型 3.针对不通的服务器和数据库特点进行SQL注入攻击 三.SQL注入攻击实例  1.字符串拼接查询,造成注入 import pymysql conn = pymysql.connect(host='127.0.0.1', port=

PL/SQL教程(转)

课程 一 PL/SQL 基本查询与排序 本课重点:   1.写SELECT语句进行数据库查询   2.进行数学运算   3.处理空值   4.使用别名ALIASES   5.连接列   6.在SQL PLUS中编辑缓冲,修改SQL SCRIPTS   7.ORDER BY进行排序输出.   8.使用WHERE 字段. 一.写SQL 命令:     不区分大小写.     SQL 语句用数字分行,在SQL PLUS中被称为缓冲区.     最后以:或 / 结束语句.     也可以用RUN来执行语

cursor: pin S

OTN 解释如下: cursor: pin SA session waits on this event when it wants to update a shared mutex pin and another session is currently in the process of updating a shared mutex pin for the same cursor object. This wait event should rarely be seen because a