Ø  简介

本文主要记录 MSSQL 中的游标使用示例,在有必要时方便借鉴查阅。游标一般定义在某段功能性的 SQL 语句中,或者存储过程中。之所以选择用它,是因为有时候无法使用简单的 SQL 语句满足我们需求,比如需要对结果集中的每一条数据,根据不同条件进行不同操作(CRUD),这时我们就可以使用游标来完成。

提示:来之 DBA 的杰作,哈哈~~

1.   示例1:

本示例,用于初始化某新表的数据。使用游标遍历查询结果集,根据遍历的数据再插入另外两张表。SQL 代码如下:

IF(OBJECT_ID('SP_Init_CustomerNewOpening', :

1)   本示例,创建了一个存储过程,创建了两个游标。

2)   第一个游标,使用游标完成更新遍历的记录,再使用遍历的数据完成对另外两张表的 Insert 操作。

3)   第二个游标,完成对3张表的更新操作,在示例中使用了当前游标记录作为更新条件,例如:WHERE CURRENT OF cursor_Crm_Refundment。

4)   该存储过程用于定时任务执行,比在程序中去查询数据,然后再遍历写入数据效率上还是比较有优势的,而且便于维护。SQL 代码如下:

IF(OBJECT_ID('SP_Add_CustomerNewOpening', 'P') IS NOT NULL)

DROP PROCEDURE SP_Add_CustomerNewOpening;

GO

CREATE PROCEDURE SP_Add_CustomerNewOpening

(

@StartTime datetime,                --开始时间

@EndTime datetime                   --结束时间

)

AS

DECLARE @Remark varchar(8000) = NULL;

INSERT INTO Sys_DbLog(LogTime, Type, Item, Message, Remark) VALUES(GETDATE(), 'info', 'SP_Add_CustomerNewOpening', '存储过程执行开始', NULL);

DECLARE @RewardsMoney decimal(18,2) = CAST(ISNULL((SELECT Value FROM Config WHERE Id=79), '0') AS decimal(18,2));

DECLARE @NewOpenMoney decimal(18,2) = CAST(ISNULL((SELECT Value FROM Config WHERE Id=80), '0') AS decimal(18,2));

DECLARE @AddCustNewOpenCount int = 0, @AddOrderNewOpenCount int = 0, @UpdateCustNewOpenCount int = 0,

@UpdateOrderNewOpenCount int = 0, @UpdateRefundmentCount int = 0;

BEGIN TRY

BEGIN TRANSACTION;

--1. 新增新开客户

DECLARE @OrderNewOpenId int, @CustNewOpenId int;

DECLARE @UserId bigint, @PayTime datetime, @Address nvarchar(500), @CustomerId bigint, @EmplCityId int, @EmployeeId int, @RealTotal decimal(18,2);

DECLARE cursor_CustomerNewOpening CURSOR GLOBAL SCROLL DYNAMIC SCROLL_LOCKS

FOR SELECT UserId, PayTime, Address, CustomerId, EmplCityId, EmployeeId, SUM(RealTotal) AS RealTotal FROM

(

SELECT t1.UserId, t1.PayTime, t1.Address, t2.CustomerId, t4.CityId AS EmplCityId, t4.EmployeeId, t1.RealTotal FROM Orders AS t1

INNER JOIN UserInfo AS t2 ON(t1.UserId = t2.Id)

INNER JOIN Customer AS t3 ON(t2.CustomerId = t3.Id)

INNER JOIN Sys_EmployeeProfile AS t4 ON(t1.SalesUserId = t4.EmployeeId)

WHERE 1=1

AND t1.UserId > 0

AND t2.CustomerId > 0

AND t1.SalesUserId > 0

AND (t1.OrderStatusId > 1 AND t1.OrderStatusId < 10)

AND (t1.PayStatusId = 2 AND t1.PayTime >= @StartTime AND t1.PayTime <= @EndTime)

AND NOT EXISTS(SELECT TOP 1 1 FROM Crm_CustomerNewOpening AS T WHERE T.CustomerId = t2.CustomerId AND (T.NewOpenStatus = 1 OR T.NewOpenStatus = 4))

AND NOT EXISTS(SELECT TOP 1 1 FROM Crm_OrderNewOpening AS T WHERE T.OrderId = t1.Id)

) AS T WHERE 1=1

AND RealTotal >= @NewOpenMoney

GROUP BY UserId, PayTime, Address, CustomerId, EmplCityId, EmployeeId;

OPEN cursor_CustomerNewOpening;

FETCH FIRST FROM cursor_CustomerNewOpening INTO @UserId, @PayTime, @Address, @CustomerId, @EmplCityId, @EmployeeId, @RealTotal;

WHILE(@@FETCH_STATUS = 0)

BEGIN

--防止本次执行多条符合的情况

IF(NOT EXISTS(SELECT TOP 1 1 FROM Crm_CustomerNewOpening AS T WHERE T.CustomerId = @CustomerId AND (T.NewOpenStatus = 1 OR T.NewOpenStatus = 4)))

BEGIN

--插入客户新开

INSERT INTO Crm_CustomerNewOpening(CustomerId, EmplCityId, EmployeeId, RewardsMoney, NewOpenMoney, RealTotal,

RefundmentMoney, PayTime, NewOpenStatus, AuditorId, AuditorTime, AuditDesc, CreateTime, UpdateTime)

VALUES(@CustomerId, @EmplCityId, @EmployeeId, @RewardsMoney, @NewOpenMoney, @RealTotal,

0, @PayTime, 1/*当前有效*/, NULL, NULL, NULL, GETDATE(), NULL);

SELECT @CustNewOpenId = SCOPE_IDENTITY(), @AddCustNewOpenCount = (@AddCustNewOpenCount + @@ROWCOUNT);

--插入订单新开

INSERT INTO Crm_OrderNewOpening(CustNewOpenId, OrderId, OrderNum, RealTotal, RefundmentMoney, CreateTime, UpdateTime)

SELECT @CustNewOpenId, t1.Id, t1.OrderNum, t1.RealTotal, 0, GETDATE(), NULL FROM Orders AS t1

WHERE 1=1

AND t1.UserId = @UserId

AND t1.PayTime = @PayTime

AND t1.Address = @Address;

SELECT @AddOrderNewOpenCount = (@AddOrderNewOpenCount + @@ROWCOUNT);

END

FETCH NEXT FROM cursor_CustomerNewOpening INTO @UserId, @PayTime, @Address, @CustomerId, @EmplCityId, @EmployeeId, @RealTotal;

END

CLOSE cursor_CustomerNewOpening;

DEALLOCATE cursor_CustomerNewOpening;

--2. 更新客户新开(退款失效)

DECLARE @RefundmentId int, @OrderId bigint, @RefundmentMoney decimal(18,2);

DECLARE cursor_Crm_Refundment CURSOR GLOBAL SCROLL DYNAMIC SCROLL_LOCKS

FOR SELECT Id, OrderId, RefundmentMoney FROM Crm_Refundment AS t1 WHERE t1.OrderNewOpenId IS NULL

AND t1.CreateTime >= @StartTime AND t1.CreateTime <= @EndTime

FOR UPDATE OF OrderNewOpenId, UpdateTime;

OPEN cursor_Crm_Refundment;

FETCH FIRST FROM cursor_Crm_Refundment INTO @RefundmentId, @OrderId, @RefundmentMoney;

WHILE(@@FETCH_STATUS = 0)

BEGIN

SELECT @OrderNewOpenId = NULL, @CustNewOpenId = NULL;

SELECT @OrderNewOpenId = Id, @CustNewOpenId = CustNewOpenId FROM Crm_OrderNewOpening WHERE OrderId = @OrderId;

IF(@OrderNewOpenId IS NOT NULL AND @CustNewOpenId IS NOT NULL)

BEGIN

DECLARE @RowCount1 int = 0, @RowCount2 int = 0;

--1. 更新订单新开

UPDATE Crm_OrderNewOpening SET RefundmentMoney = (RefundmentMoney + @RefundmentMoney), UpdateTime = GETDATE()

WHERE Id = @OrderNewOpenId;

SELECT @RowCount1 = @@ROWCOUNT, @UpdateOrderNewOpenCount = (@UpdateOrderNewOpenCount + @@ROWCOUNT);

--2. 更新客户新开

UPDATE Crm_CustomerNewOpening SET RefundmentMoney = (RefundmentMoney + @RefundmentMoney),

NewOpenStatus = (CASE WHEN NewOpenStatus = 1 AND (RealTotal - (RefundmentMoney + @RefundmentMoney)) < @NewOpenMoney

THEN 2 ELSE NewOpenStatus END)/*只有【当前有效】状态才更新状态*/,

RefundmentId = (CASE WHEN NewOpenStatus = 1 AND (RealTotal - (RefundmentMoney + @RefundmentMoney)) < @NewOpenMoney

--AND RefundmentId IS NULL/*逻辑上可以省略该条件,因为。。。*/

THEN @RefundmentId ELSE RefundmentId END)/*记录导致退款失效的退款Id*/,

UpdateTime = GETDATE()

WHERE Id = @CustNewOpenId;

SELECT @RowCount2 = @@ROWCOUNT, @UpdateCustNewOpenCount = (@UpdateCustNewOpenCount + @@ROWCOUNT);

IF(@RowCount1 = 1 AND @RowCount2 = 1)

BEGIN

UPDATE Crm_Refundment SET OrderNewOpenId = @OrderNewOpenId, UpdateTime = GETDATE() WHERE CURRENT OF cursor_Crm_Refundment;

SELECT @UpdateRefundmentCount = (@UpdateRefundmentCount + @@ROWCOUNT);

END

END

FETCH NEXT FROM cursor_Crm_Refundment INTO @RefundmentId, @OrderId, @RefundmentMoney;

END

CLOSE cursor_Crm_Refundment;

DEALLOCATE cursor_Crm_Refundment;

COMMIT;

SET @Remark = '新开客户数:' + CAST(@AddCustNewOpenCount AS varchar(20))

+ ',新开订单数:' + CAST(@AddOrderNewOpenCount AS varchar(20))

+ ',更新新开客户数:' + CAST(@UpdateCustNewOpenCount AS varchar(20))

+ ',更新新开订单数:' + CAST(@UpdateOrderNewOpenCount AS varchar(20))

+ ',更新退款数:' + CAST(@UpdateRefundmentCount AS varchar(20));

INSERT INTO Sys_DbLog(LogTime, Type, Item, Message, Remark) VALUES(GETDATE(), 'info', 'SP_Add_CustomerNewOpening', '存储过程执行结束', @Remark);

END TRY

BEGIN CATCH

ROLLBACK;

DECLARE @Message varchar(8000) = '错误:[' + CAST(ERROR_LINE() AS nvarchar(20)) + '],' + ERROR_MESSAGE();

INSERT INTO Sys_DbLog(LogTime, Type, Item, Message, Remark) VALUES(GETDATE(), 'error', 'SP_Add_CustomerNewOpening', @Message, '事物已回滚');

END CATCH

GO

SQL Server 游标的使用示例的更多相关文章

  1. SQL Server游标 C# DataTable.Select() 筛选数据 什么是SQL游标? SQL Server数据类型转换方法 LinQ是什么? SQL Server 分页方法汇总

    SQL Server游标   转载自:http://www.cnblogs.com/knowledgesea/p/3699851.html. 什么是游标 结果集,结果集就是select查询之后返回的所 ...

  2. SQL Server 游标运用:鼠标轨迹字符串分割

    一.本文所涉及的内容(Contents) 本文所涉及的内容(Contents) 背景(Contexts) 游标模板(Cursor Template) 鼠标轨迹字符串分割SQL脚本实现(SQL Code ...

  3. sql server 游标的简单用法

    sql server游标: --定义游标 declare cursor1 cursor for select ID,Name from A --打开游标 open cursor1 declare @i ...

  4. SQL Server 游标运用:查看所有数据库所有表大小信息(Sizes of All Tables in All Database)

    原文:SQL Server 游标运用:查看所有数据库所有表大小信息(Sizes of All Tables in All Database) 一.本文所涉及的内容(Contents) 本文所涉及的内容 ...

  5. SQL Server 游标运用:查看一个数据库所有表大小信息(Sizes of All Tables in a Database)

    原文:SQL Server 游标运用:查看一个数据库所有表大小信息(Sizes of All Tables in a Database) 一.本文所涉及的内容(Contents) 本文所涉及的内容(C ...

  6. 学习使用MS SQL Server游标(CURSOR)

    说实的,使用MS SQL Server这样久,游标一直没有使用过.以前实现相似的功能,都是使用WHILE循环加临时表来实现.刚才有参考网上示例练习写了一下.了解到游标概念与语法. 下面代码示例中,先是 ...

  7. Sql Server 游标概念与实例

    引言 先不讲游标的什么概念,看如下Sql Server2008 图例: 需求:两张表的O_ID是一一对应的,现在求将加薪的工资+原来的工资=现在的工资,也就是O_Salary=O_Salary+A_S ...

  8. 2009-04-19 22:40 SQL SERVER游标的讲解

    游标和游标的优点 在数据库中,游标是一个十分重要的概念.游标提供了一种对从表中检索出的数据进行操作的灵活手段,就本质而言,游标实际上是一种能从包括多条数据记录的结 果集中每次提取一条记录的机制.游标总 ...

  9. SQL Server游标(转)

    清晰地介绍了SQL游标,很好的学习资料. 转自 http://www.cnblogs.com/knowledgesea/p/3699851.html 什么是游标 结果集,结果集就是select查询之后 ...

随机推荐

  1. Spark 基本函数学习笔记一

      Spark 基本函数学习笔记一¶ spark的函数主要分两类,Transformations和Actions. Transformations为一些数据转换类函数,actions为一些行动类函数: ...

  2. 移动端click延迟和tap事件

    一.click等事件在移动端的延迟 click事件在移动端和pc端均可以触发,但是在移动端有延迟现象. 1.背景 由于早期移动设备浏览网页时内容较小,为了增强用户体验,苹果公司专门为移动设备设计了双击 ...

  3. 如何快速搭建一个基于ServiceStack框架的web服务

    ServiceStack是一个高性能的.NET Web Service 平台,能够简化开发高性能的REST (支持JSON,XML,JSV,HTML,MsgPack,ProtoBuf,CSV等消息格式 ...

  4. react this的作用域问题,麻烦大佬们帮我解决一下

    element里面有个Table组件,我想在编辑和删除那里加上点击事件,但是发现点击方法没有效果 这里面的this看起来好像只针对这个作用域里面的,这里没有办法设置状态,也不能调用方法 设置状态会出现 ...

  5. MATLAB中“fitgmdist”的用法及其GMM聚类算法

    MATLAB中“fitgmdist”的用法及其GMM聚类算法 作者:凯鲁嘎吉 - 博客园http://www.cnblogs.com/kailugaji/ 高斯混合模型的基本原理:聚类——GMM,MA ...

  6. 阿狸V任务页面爬取数据解析

    需求: 爬取:https://v.taobao.com/v/content/video 所有主播详情页信息 首页分析 分析可以得知数据是通过ajax请求获取的. 分析请求头 详情页分析 详情页和详情页 ...

  7. gVim编辑器 模板篇

    上文介绍了gVim的常用操作,这次总结一下我自己常用的模板. 安装和配置好gVim后,在Program Files (x86)\Vim目录下有个“_vimrc”文件,双击选择gVim软件打开,在里面添 ...

  8. handsontable的基础应用

    handsontable是一款页面端的表格式交互插件,可以通过她加载显示表格内容,能够支持合并项.统计.行列拖动等. 同时,支持对加载后的表格页面的处理:添加/删除行/列,合并单元格等操作. 我在项目 ...

  9. day09(垃圾回收机制)

    1,复习 文件处理 1.操作文件的三步骤 -- 打开文件:硬盘的空间被操作系统持有 | 文件对象被应用程序持续 -- 操作文件:读写操作 -- 释放文件:释放操作系统对硬盘空间的持有 2.基础的读写 ...

  10. css文字与排版

    目录 文字与排版样式 `font文字样式 排版样式(text) 文字半透明 文字阴影 背景和颜色 基本 背景简写 背景透明 背景缩放 列表样式 表格样式 表格边框样式 折叠边框 设置宽度和高度 表格对 ...