sqlserver常用知识点备忘录
背景 一个项目的开发,离不开数据库的相关操作,表/视图设计,存储过程,触发器等等数据库对象的操作是非常频繁的。有时候,我们会查找系统中类似的代码,然后复制/粘贴进行再进行相应的修改。本文的目的在于归纳、总结sqlserver数据库的常用操作,并不断更新。期以备忘! P1 sql的执行顺序 sql语句是操作数据库的工具,了解sql的执行顺序会极大地帮助我们提高我们编写的sql的执行效率。见以下代码: (8)SELECT (9)DISTINCT (11)<Top Num> select list> (1)FROM [left_table] (3)<join_typeJOIN <right_table2)ON <join_condition4)WHERE <where_condition5)GROUP BY <group_by_list6)WITH <CUBE | RollUP7)HAVING <having_condition10)ORDER <order_by_list>
总的来说,select的列是最后一步被执行的,而From的Table是首先被执行的。 P2 创建带Try。。。Catch的存储过程模板 Copy下面的代码,然后新建查询,就可以写sql语句,执行完后,一个你自己的存储过程就建立好了! USE DB]--设定对应的数据库 GO SET ANSI_NULLS ON SET QUOTED_IDENTIFIER ============================================= -- AUTHOR: DESCRIBE: ============================================= CREATE PROCEDURE dbo].UP_InsertJHBData] 存储过程名 ( @CustomerName VARCHAR(50) 参数 ) AS BEGIN SET NOCOUNT ON 提高性能的,必须要有 DECLARE @Now DATETIME SET @Now = GETDATE() 所有操作保证统一时间 BEGIN TRY 在这里写SQL END TRY BEGIN CATCH @ErrorMessage NVARCHAR(4000) ; @ErrorSeverity INT ; @ErrorState INT ; SELECT @ErrorMessage = ERROR_MESSAGE(),@ErrorSeverity = ERROR_SEVERITY(),0); line-height:1.5!important">@ErrorState = ERROR_STATE() ; PRINT @ErrorMessage RAISERROR(@ErrorMessage, Message text. @ErrorSeverity,128); line-height:1.5!important"> Severity. @ErrorState State. ) ; RETURN -1 ; END CATCH END P3 创建带事务的存储过程模板 只是将带Try。。。Catch的存储过程的模板中加入了事务的控制,使用类似 ] GO 存储过程名参数 ( 50) ) 参数 BEGIN ON ;DATETIME ; GETDATE() ;所有操作保证统一时间 BEGIN TRY BEGIN TRANSACTION myTrans ;开始事务 在这里写SQL COMMIT 事务提交语句 BEGIN CATCH ROLLBACK TRANSACTION myTrans 始终回滚事务 抛出异常 Message text. Severity. State. ) ; P4 批量插入或者生成测试数据,或者填充临时表,我们都会碰到批量插入表的需求,此时,针对被插入的表是否存在分以下两种情况:
P5 批量更新 链接两个表,通过第一张表的数据去批量地更新第二张表,使用以下的sql UPDATE t2 SET t2.FirstSaleOrderDate = t1.FirstSaleOrderDate,t2.LastSaleOrderDate = t1.LastSaleOrderDate FROM #T_ValidSODate t1 INNER JOIN #T_PendingReport t2 ON t1.GiftCardNO = t2.GiftCardNO P6 循环模板 在存储过程中,经常会生成一些临时表,然后循环临时表的数据进行处理,以下模板可以帮助伙伴们快速处理此类需求 --生成带行号的临时表数据,并插入临时表#T_Table中 SELECT ROW_NUMBER() OVER (BY ID) AS RowNum,NAME INTO #T_Table FROM TableName 获取记录总数 @RecordCount INT = 0 SELECT @RecordCount COUNT(1) FROM #T_Table @CurrRowNum 1 当前行号 @CurrName 50) 当前字段 循环记录 WHILE @CurrRowNum <= @RecordCount BEGIN 获取当前记录 @CurrName = Name FROM #T_Table WHERE RowNum = @CurrRowNum 自定义sql + 1 到下一条记录 ENDP7 字符串转表函数 下面的函数的功能是将【a;b;c;】这样的字符串按照【;】进行分割并返回一张表 Util/****** Object: UserDefinedFunction [dbo].[Func_StringListToTable] Script Date: 04/08/2014 10:59:53 ******/ Author: Create date: Description: 将字符串转换为表 调用示例如下 DECLARE @StringList NVARCHAR(max) SET @StringList='a;b;c;' DECLARE @Split VARCHAR(10) SET @Split=';' SELECT * FROM Util.dbo.[Func_StringListToTable](@StringList,@Split)FUNCTION Func_StringListToTable] ( Add the parameters for the function here @StringList NVARCHAR(MAX),0); line-height:1.5!important">@split 10) ) RETURNS @StringTable TABLE ( ID INT,String VARCHAR(MAX) ) BEGIN Fill the table variable with the rows for your result set @i INT @i 1 WHILE ( CHARINDEX(@split,0); line-height:1.5!important">@StringList) <> 0 ) BEGIN INSERT @StringTable ( ID,String ) VALUES ( @i,SUBSTRING(@StringList,1,128); line-height:1.5!important">- 1) ) @StringList STUFF(@StringList) + LEN(@split) 1,'') 1 END IF <> '' BEGIN @i,0); line-height:1.5!important">@StringList ) END RETURN P8 分组数据集并返回每个组的前n条记录Row_NUMBER()函数用于生成行号;利用PARTITION BY可以将结果集按照指定需求进行分组;最终使用一个简单的子查询就能够获取每组的前3条数据 SELECT * FROM ( SELECT ROW_NUMBER() OVER ( PARTITION BY ProductNO BY ProductNO ) * FROM IM.dbo.ItemInfo ) t WHERE t.RowNum IN ( 2,0); line-height:1.5!important">3 )P9 【用户自定义表类型】的使用 您是否碰到过这样的需求:调用存储过程的时候传一张表进去??? 在sqlserver数据库中有一种称为【用户自定义表类型】的数据结构 以下代码实现了在IM数据库中新建一个名称为GCRP_PendingGiftCard_TYPE的用户自定义表结构: IM***** Object: UserDefinedTableType [dbo].[GCRP_PendingGiftCard_TYPE] Script Date: 04/08/2014 14:56:16 *****CREATE TYPE GCRP_PendingGiftCard_TYPE] AS TABLE( RowNum] intNULL,0); line-height:1.5!important">GiftCardNOvarchar](500) UsedDatedatetimeCustomerName50) ReduceAmountdecimal18,0); line-height:1.5!important">2) AmountNULL ) GO下面的代码演示了【用户自定义表类型】的使用方式和场景(使用起来和临时表、表变量类似) 1 声明一个自定义表类型@T_PendingGiftCard @T_PendingGiftCard GCRP_PendingGiftCard_TYPE 2 执行一个存储过程,并把返回的结果集插入到上面声明的自定义表类型@T_PendingGiftCard中 INTO @T_PendingGiftCard EXEC IM.dbo.UP_GCRP_GetEntireGfitCardWithReduceAmount 3 声明一个自定义表类型@T_PendingSO @T_PendingSO GCRP_PendingSO_TYPE 4 执行一个存储过程,传入表类型@T_PendingGiftCard,并把返回的结果集插入自定义表类型@T_PendingSO中 @T_PendingSO EXEC IM.dbo.UP_GCRP_GetEntireSOWithGiftCardUsed @T_PendingGiftCard 下面贴出这两个存储过程的源码,供大家参考 ***** Object: StoredProcedure [dbo].[UP_GCRP_GetEntireSOWithGiftCardUsed] Script Date: 04/08/2014 15:02:50 *****GO Author: DeanZhou Create date: 2014-04-04 Description: 获取礼品卡报表数据-获取使用礼品卡的订单信息ALTER UP_GCRP_GetEntireSOWithGiftCardUsed@T_PendingGiftCard GCRP_PendingGiftCard_TYPE READONLY ) BEGIN 提高性能的,必须要有 订单状态:1 待审核 2 待支付 3 已支付,待确认 4 已支付 5 出库中 6 已发货 7 已收货 8 换货中 9 退货中 10 已换货 11 已退货 12 退款成功 13 换货被拒绝 14 退货被拒绝 15 交易成功 16 订单已关闭 17 客户作废 18 商城作废 19 系统自动作废 20 退款中 21 等待团购成功 22 组团失败 SELECT S.SONO,128); line-height:1.5!important"> 订单编号 VARCHAR(30) S.EwalletDiscountAmount,128); line-height:1.5!important"> 电子钱包支付金额 DECIMAL(18,2) S.RefundAmount,128); line-height:1.5!important"> 发生退款的总金额 DECIMAL(18,2) ( S.EwalletDiscountAmount + S.RefundAmount ) AS RealUsedAmount,128); line-height:1.5!important"> 实际使用电子钱包的金额 DECIMAL(18,2) 0 AS RelatedRefundID,S.CustomerName,128); line-height:1.5!important"> 客户名称 VARCHAR(50) S.SaleOrderStatus,128); line-height:1.5!important"> 订单状态 INT S.CreateDate 下单日期 DATETIME INTO #T_PendingSO SELECT A.SONO,A.EwalletDiscountAmount,( SELECT -ISNULL(SUM(B.Amount),0); line-height:1.5!important">0) FROM RMA.dbo.RefundRecord B WHERE B.SONO = A.SONO AND B.RefundType 3 AND B.Status 3,0); line-height:1.5!important">4 ) ) AS RefundAmount,255); line-height:1.5!important">CONVERT(DECIMAL(2),0); line-height:1.5!important">0) AS RealUsedAmount,A.CustomerName,A.SaleOrderStatus,A.CreateDate FROM SO.dbo.SOMaster A WHERE EwalletDiscountAmount 0 AND SaleOrderStatus NOT 17,0); line-height:1.5!important">19 ) AND EXISTS ( SELECT 1 FROM @T_PendingGiftCard C WHERE A.CustomerName = C.CustomerName AND A.CreateDate > C.UsedDate ) 1 FROM IM.dbo.Temp_UsedGiftCardReportDetail B WHERE A.SONO = B.SONO AND B.UsedAmount 0 ) ) S DELETE IM.dbo.Temp_UsedGiftCardReportDetail WHERE UsedAmount <= 0 EXISTS (FROM #T_PendingSO B WHERE Temp_UsedGiftCardReportDetail.SONO = B.SONO ) SELECT ROW_NUMBER() OVER ( BY S.CustomerName,S.SONO,S.CreateDate ASC ) * * FROM #T_PendingSO UNION ALL -A.Amount FROM RMA.dbo.RefundRecord A JOIN #T_PendingSO B ON A.SONO = B.SONO WHERE A.RefundType 3 AND A.Status 4 ) AS EwalletDiscountAmount,B.UsedAmount,128); line-height:1.5!important">JOIN IM.dbo.Temp_UsedGiftCardReportDetail B = B.SONO 0 4 ) ) S END (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |