1. 程式人生 > >幾個很好用SQL語法(SqlServer)

幾個很好用SQL語法(SqlServer)

base class ESS lse 簡單 table 可能 錯誤 mat

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

幾個很好用SQL語法(SqlServer)