几个很好用SQL语法(SqlServer)

1,MERGE INTO 语句:

这个语法仅需要一次全表扫描就完成了全部工作,执行效率要高于INSERT+UPDATE,作用还是很强大的(简单的说就是它可以批量更新和插入处理一个数据集,如果存在就更新指定列,不存在就插入)

/****** MERGE INTO 语句运用实例 ******/
-- =============================================
-- Author:        <Author,yuanchen,Name>
-- Create date: <Create Date,,>
-- Description:    <Description,将数据批量新增或更新到[dbo].[Table]中,ID为主键自增>
-- =============================================
Create PROCEDURE [dbo].[AddOrUpdateTable]
    @Roles UDT_Table READONLY,--用户自定义表类型(相当于一个传入的临时表)
    @ReturnValue INT OUTPUT  --返回值
AS
BEGIN
    SET NOCOUNT ON;
    BEGIN TRY
    BEGIN TRANSACTION
        MERGE INTO [dbo].[Table] AS TARGET --此处[dbo].[Table]是需要插入或更新数据的表
        USING (SELECT * FROM @UDT_Table) AS SOURCE
            ON TARGET.ID = SOURCE.ID --根据此处的列作为条件判断是新增还是更新(多个列作为条件用and连接)
        WHEN MATCHED
        THEN UPDATE 
        SET 
            TARGET.[A]=SOURCE.[B],
            TARGET.[B]=SOURCE.[B],
            TARGET.[UpdateTime]=getdate() --内置函数获取当前时间
        WHEN NOT MATCHED 
        THEN INSERT 
            ([A],[B],[CreateTime])
            VALUES(SOURCE.[A],SOURCE.[B],getdate());  
        SET @ReturnValue = 1 
    COMMIT TRAN
    END TRY
    BEGIN CATCH
      IF XACT_STATE() <> 0
        BEGIN
          ROLLBACK TRANSACTION;
          --此处可以用Error_message()函数记录日志,千万不要在ROLLBACK TRANSACTION前面记录日志,会被回滚
          SET @ReturnValue = -1
        END;
    END CATCH  
END

2,WITH XXX AS  语句:

WITH AS短语,也叫做子查询部分(subquery factoring),可以让你做很多事情,定义一个SQL片断,该SQL片断会被整个SQL语句所用到。有的时候,是为了让SQL语句的可读性更高些,也有可能是在UNION ALL的不同部分,作为提供数据的部分。 
特别对于UNION ALL比较有用。因为UNION ALL的每个部分可能相同,但是如果每个部分都去执行一遍的话,则成本太高,所以可以使用WITH AS短语,则只要执行一遍即可。如果WITH AS短语所定义的表名被调用两次以上,则优化器会自动将WITH AS短语所获取的数据放入一个TEMP表里,如果只是被调用一次,则不会。而提示materialize则是强制将WITH AS短语里的数据放入一个全局临时表里。很多查询通过这种方法都可以提高速度。(更高效,可读性更好,复杂的子查询推荐使用)

With [Table1] As(
    select * from [A] inner join [B] on [A].ID=B.[A_ID] --A表和B表连表查询
),[Table2] As(
    select * from [C] inner join [Table1] T on [C].ID=T.[C_ID] --C表和A,B表的查询结果连表查询
)Select * From [Table2]
 
 --上面的查询结果等同于下面这段Sql
 select * from [C] inner join (select * from [A] inner join [B] on [A].ID=B.[A_ID]) T on [C].ID=T.[C_ID]

3,游标的常规使用,游标可以遍历数据集对每条数据的指定列做处理,处理数据的能力也是相当强大的,但是滥用和使用不当可能对造成性能问题哦,而且处理复杂的多表多条数据时一般都要配合事务一起使用,不然一旦程序错误就会产生错误数据

/****** 游标的使用实例  ******/
-- =============================================
-- Author:        <Author,yuanchen>
-- Create date: <Create Date,>
-- Description:    <Description,>
-- =============================================
Create Proc [dbo].[Proc_CURSOR_USE] 
AS
BEGIN
    SET NOCOUNT ON;

    DECLARE @ID BIGINT    --定义变量
    DECLARE @A BIGINT    
    DECLARE @B NVARCHAR(100) 

    Select * INTO #Table From [Table] --将查询结果放入临时表
    --定义游标
    DECLARE CURSOR_JOB01 CURSOR FOR
        Select [ID],[A],[B] From #Table --此处可以不用临时表,直接写查询语句,但在实际的业务处理中我们需要的查询结果可能是通过复杂的查询语句得到的,直接写在此处,可读性较差
       OPEN CURSOR_JOB01
       FETCH CURSOR_JOB01 INTO @ID,@A,@B
       BEGIN TRY
         BEGIN TRANSACTION    
         WHILE (@@FETCH_STATUS=0)
         BEGIN
            --此处可以逻辑代码,即对游标遍历的当前数据做处理,例如:如果当前数据列A>0,那么就向[BaseLog]表记录一条日志
            IF(@A>0)
            Begin
                 Insert into BaseLog([CONTENT],[CreateTime],[Pro_Name]) values('ID为:'+CONVERT(varchar(10),@ID)++'的A列的值大于0',getdate(),'[Proc_CURSOR_USE]'); --记录错误日志
            End
            FETCH CURSOR_JOB01 INTO @ID,@A,@B
          END
          CLOSE CURSOR_JOB01
          DEALLOCATE CURSOR_JOB01       
        COMMIT
        END TRY
        BEGIN CATCH
        IF XACT_STATE() <> 0
        BEGIN
          ROLLBACK TRANSACTION;
          Insert into BaseLog([CONTENT],[CreateTime],[Pro_Name]) values(Error_message(),getdate(),'[Proc_CURSOR_USE]'); --记录错误日志
          IF CURSOR_STATUS('local','CURSOR_JOB01') <> -3
          BEGIN       
             IF CURSOR_STATUS('local','CURSOR_JOB01') <> -1
             BEGIN
                CLOSE CURSOR_JOB01
                DEALLOCATE CURSOR_JOB01
             END
          END
      END;
   END CATCH    
    DROP TABLE #Table --清除临时表
END

猜你喜欢

转载自www.cnblogs.com/ruanraun/p/9174532.html