SQL Server 致程序員(容易忽略的錯誤)

概述 html

由於天天須要審覈程序員發佈的SQL語句,因此收集了一些程序員的一些常見問題,還有一些平時收集的其它一些問題,這也是不少人容易忽視的問題,在之後收集到的問題會補充在文章末尾,歡迎關注,因爲收集的問題不少是針對於生產數據,測試且數據量比較大,這裏就不把數據共享出來了,你們理解意思就行。 程序員

 

步驟 sql

大小寫

大寫T-SQL 語言的全部關鍵字都使用大寫,規範要求。 數據庫

使用「;」

使用「;」做爲 Transact-SQL 語句終止符。雖然分號不是必需的,但使用它是一種好的習慣,對於合併操做MERGE語句的末尾就必需要加上「;」 緩存

(cte表表達式除外) 安全

數據類型

避免使用ntext、text 和 image 數據類型,用 nvarchar(max)、varchar(max) 和 varbinary(max)替代 服務器

後續版本會取消ntext、text 和 image 該三種類型 網絡

 

查詢條件不要使用計算列

複製代碼
例如year(createdate)=2014,使用createdate>=20140101and createdate<=20141231’來取代。 
複製代碼
IF OBJECT_ID('News','U') IS NOT NULL DROP TABLE News GO CREATE TABLE News (ID INT NOT NULL PRIMARY KEY IDENTITY(1,1), NAME NVARCHAR(100) NOT NULL, Createdate DATETIME NOT NULL ) GO CREATE NONCLUSTERED INDEX [IX1_News] ON [dbo].[News] ( [Createdate] ASC ) INCLUDE ( [NAME]) WITH (STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] GO GO INSERT INTO News(NAME,Createdate) VALUES( '新聞','2014-08-20 00:00:00'),( '新聞','2014-08-20 00:00:00'),( '新聞','2014-08-20 00:00:00'),( '新聞','2014-08-20 00:00:00')
複製代碼

---使用計算列查詢(走的是索引掃描) ide

SELECT ID,NAME,Createdate FROM News WHERE YEAR(Createdate)=2014

---不使用計算列(走的是索引查找) 性能

SELECT ID,NAME,Createdate FROM News WHERE CreateDate>='2014-01-01 00:00:00' and CreateDate<'2015-01-01 00:00:00'

對比兩個查詢顯然絕大部分狀況下走索引查找的查詢性能要高於走索引掃描,特別是查詢的數據庫不是很是大的狀況下,索引查找的消耗時間要遠遠少於索引掃描的時間,若是想詳細瞭解索引的體系結構能夠查看了我前面寫的幾篇關於彙集、非彙集、堆的索引體系機構的文章。

複製代碼

 

請參看:http://www.cnblogs.com/chenmh/p/3780221.html

 請參看:http://www.cnblogs.com/chenmh/p/3782397.html

 

建表時字段不容許爲null


      發現不少人在建表的時候不會注意這一點,在接下來的工做中當你須要查詢數據的時候你每每須要在WHERE條件中多加一個判斷條件IS NOT NULL,這樣的一個條件不只僅增長了額外的開銷,並且對查詢的性能產生很大的影響,有可能就由於多了這個查詢條件致使你的查詢變的很是的慢;還有一個比較重要的問題就是容許爲空的數據可能會致使你的查詢結果出現不許確的問題,接下來咱們就舉個例子討論一下。

複製代碼
T-SQL是三值邏輯(true,flase,unknown) IF OBJECT_ID('DBO.Customer','U') IS NOT NULL DROP TABLE DBO.Customer GO CREATE TABLE DBO.Customer (Customerid int not null ); GO IF OBJECT_ID('DBO.OrderS','U') IS NOT NULL DROP TABLE DBO.OrderS GO CREATE TABLE DBO.OrderS (Orderid int not null, custid int); GO INSERT INTO Customer VALUES(1),(2),(3); INSERT INTO OrderS VALUES(1,1),(2,2),(3,NULL); ----查詢沒有訂單的顧客 SELECT Customerid FROM DBO.Customer WHERE Customerid NOT IN(SELECT custid FROM OrderS); ---分析爲何查詢結果沒有數據 /* 由於true,flase,unknown都是真值 由於not in 是須要結果中返回flase值,not true=flase,not flase=flase,not unknown=unknown 由於null值是unknown因此not unknownn沒法判斷結果是什麼值因此不能返回數據 */ --能夠將查詢語句修改成 SELECT Customerid FROM DBO.Customer WHERE Customerid NOT IN(SELECT custid FROM OrderS WHERE custid is not null); --或者使用EXISTS,由於EXISTS是二值邏輯只有(true,flase)因此不存在未知。 SELECT Customerid FROM DBO.Customer A WHERE NOT EXISTS(SELECT custid FROM OrderS WHERE OrderS.custid=A.Customerid ); ---in查詢能夠返回值,由於in是true,子查詢true,flase,unknown都是真值因此能夠返回子查詢的true SELECT Customerid FROM DBO.Customer WHERE Customerid IN(SELECT custid FROM OrderS);
複製代碼

 

分組統計時避免使用count(*)

複製代碼
IF OBJECT_ID('DBO.Customer','U') IS NOT NULL DROP TABLE DBO.Customer GO CREATE TABLE DBO.Customer (Customerid int not null ); GO IF OBJECT_ID('DBO.OrderS','U') IS NOT NULL DROP TABLE DBO.OrderS GO CREATE TABLE DBO.OrderS (Orderid int not null, custid int); GO INSERT INTO Customer VALUES(1),(2),(3); INSERT INTO OrderS VALUES(1,1),(2,2),(3,NULL); 例如:須要統計每個顧客的訂單數量 ---若是使用count(*) SELECT Customerid,COUNT(*) FROM Customer TA LEFT JOIN OrderS TB ON TA.Customerid=TB.custid GROUP BY Customerid ;

實際狀況customerid=3是沒有訂單的,數量應該是0,可是結果是1

----正確的方法是使用count(custid) SELECT Customerid,COUNT(custid) FROM Customer TA LEFT JOIN OrderS TB ON TA.Customerid=TB.custid GROUP BY Customerid;

 

複製代碼

 

子查詢的表加上表別名

複製代碼
IF OBJECT_ID('DBO.Customer','U') IS NOT NULL DROP TABLE DBO.Customer GO CREATE TABLE DBO.Customer (Customerid int not null ); GO IF OBJECT_ID('DBO.OrderS','U') IS NOT NULL DROP TABLE DBO.OrderS GO CREATE TABLE DBO.OrderS (Orderid int not null, custid int); GO INSERT INTO Customer VALUES(1),(2),(3); INSERT INTO OrderS VALUES(1,1),(2,2),(3,NULL);
複製代碼

你們發現下面語句有沒有什麼問題,查詢結果是怎樣呢?

SELECT Customerid FROM Customer WHERE Customerid IN(SELECT Customerid FROM OrderS WHERE Orderid=2 );


正確查詢結果下查詢出的結果是沒有customerid爲3的值

爲何結果會這樣呢?

你們仔細看應該會發現子查詢的orders表中沒有Customerid字段,因此SQL取的是Customer表的Customerid值做爲相關子查詢的匹配字段。

因此咱們應該給子查詢加上表別名,若是加上表別名,若是字段錯誤的話會有錯誤標示

 正確的寫法:

SELECT Customerid FROM Customer WHERE Customerid IN(SELECT tb.custid FROM OrderS tb WHERE Orderid=2 );

創建自增列時單獨再給自增列添加惟一約束

複製代碼
複製代碼
USE tempdb CREATE TABLE TEST (ID INT NOT NULL IDENTITY(1,1), orderdate date NOT NULL DEFAULT(CURRENT_TIMESTAMP), NAME NVARCHAR(30) NOT NULL, CONSTRAINT CK_TEST_NAME CHECK(NAME LIKE '[A-Za-z]%' ) ); GO INSERT INTO tempdb.DBO.TEST(NAME) VALUES('A中'),('a名'),('Aa'),('ab'),('AA'),('az'); ----4.插入報錯後,自增值依舊增長 INSERT INTO tempdb.DBO.TEST(NAME) VALUES(''); GO SELECT IDENT_CURRENT('tempdb.DBO.TEST'); SELECT * FROM tempdb.DBO.TEST; ---插入正常的數據 INSERT INTO tempdb.DBO.TEST(NAME) VALUES('cc'); SELECT IDENT_CURRENT('tempdb.DBO.TEST') SELECT * FROM tempdb.DBO.TEST; ----5.顯示插入自增值 SET IDENTITY_INSERT tempdb.DBO.TEST ON INSERT INTO tempdb.DBO.TEST(ID,NAME) VALUES(8,'A中'); SET IDENTITY_INSERT tempdb.DBO.TEST OFF ----會發現ID並非根據自增值排列的,並且根據插入的順序排列的 SELECT IDENT_CURRENT('tempdb.DBO.TEST'); SELECT * FROM tempdb.DBO.TEST; ----6.插入重複的自增值 SET IDENTITY_INSERT tempdb.DBO.TEST ON INSERT INTO tempdb.DBO.TEST(ID,NAME) VALUES(8,'A中'); SET IDENTITY_INSERT tempdb.DBO.TEST OFF SELECT IDENT_CURRENT('tempdb.DBO.TEST') SELECT * FROM tempdb.DBO.TEST; ---因此若是要保證ID是惟一的,單單隻設置自增值不行,須要給字段設置主鍵或者惟一約束 DROP TABLE tempdb.DBO.TEST;
複製代碼

 

複製代碼

 

查詢時必定要制定字段查詢

l  查詢時必定不能使用」*」來代替字段來進行查詢,不管你查詢的字段有多少個,就算字段太多沒法走索引也避免瞭解析」*」帶來的額外消耗。

l  查詢字段值列出想要的字段,避免出現多餘的字段,字段越多查詢開銷越大並且可能會由於多列出了某個字段而引發查詢不走索引。

建立測試數據庫

複製代碼
CREATE TABLE [Sales].[Customer]( [CustomerID] [int] IDENTITY(1,1) NOT FOR REPLICATION NOT NULL, [PersonID] [int] NULL, [StoreID] [int] NULL, [TerritoryID] [int] NULL, [AccountNumber] AS (isnull('AW'+[dbo].[ufnLeadingZeros]([CustomerID]),'')), [rowguid] [uniqueidentifier] ROWGUIDCOL NOT NULL, [ModifiedDate] [datetime] NOT NULL, CONSTRAINT [PK_Customer_CustomerID] PRIMARY KEY CLUSTERED ( [CustomerID] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY]
複製代碼

建立索引

複製代碼
CREATE NONCLUSTERED INDEX [IX1_Customer] ON [Sales].[Customer] ( [PersonID] ASC ) INCLUDE ( [StoreID], [TerritoryID], [AccountNumber], [rowguid]) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] GO
複製代碼

查詢測試

複製代碼
---使用SELECT * 查詢 SET STATISTICS IO ON SET STATISTICS TIME ON SELECT * FROM [Sales].[Customer] WHERE PersonID=1; SET STATISTICS TIME OFF SET STATISTICS IO OFF
複製代碼

因爲建的索引‘IX1_Customer’沒有包含ModifiedDate字段,因此須要經過鍵查找去彙集索引中獲取該字段的值

複製代碼
---列出須要的字段查詢,由於字段不包含不須要的列,因此走索引 SET STATISTICS IO ON SET STATISTICS TIME ON SELECT CustomerID, [PersonID] ,[StoreID] ,[TerritoryID] ,[AccountNumber] ,[rowguid] FROM [Sales].[Customer] WHERE PersonID=1; SET STATISTICS TIME OFF SET STATISTICS IO OFF
複製代碼

因爲查詢語句中沒有對ModifiedDate字段進行查詢,因此只走索引查找就能夠查詢到須要的數據,因此建議在查詢語句中列出你須要的字段而不是爲了方便用*來查詢全部的字段,若是真的

須要查詢全部的字段也一樣建議把全部的字段列出來取代‘*’。

 

使用存儲過程的好處

  1. 減小網絡通訊量。調用一個行數很少的存儲過程與直接調用SQL語句的網絡通訊量可能不會有很大的差異,但是若是存儲過程包含上百行SQL語句,那麼其性能絕對比一條一條的調用SQL語句要高得多。
  2. 執行速度更快。有兩個緣由:首先,在存儲過程建立的時候,數據庫已經對其進行了一次解析和優化。其次,存儲過程一旦執行,在內存中就會保留一份這個存儲過程緩存計劃,這樣下次再執行一樣的存儲過程時,能夠從內存中直接調用。
  3. 更強的適應性:因爲存儲過程對數據庫的訪問是經過存儲過程來進行的,所以數據庫開發人員能夠在不改動存儲過程接口的狀況下對數據庫進行任何改動,而這些改動不會對應用程序形成影響。
  4. 布式工做:應用程序和數據庫的編碼工做能夠分別獨立進行,而不會相互壓制。
  5. 更好的封裝移植性。
  6. 安全性,它們能夠防止某些類型的 SQL 插入攻擊。
複製代碼
PROCEDURE [dbo].[SPSalesPerson] (@option varchar(50)) AS BEGIN SET NOCOUNT ON IF @option='select' BEGIN SELECT [DatabaseLogID] ,[PostTime] ,[DatabaseUser] ,[Event] ,[Schema] ,[Object] ,[TSQL] ,[XmlEvent] FROM [dbo].[DatabaseLog] END IF @option='SalesPerson' BEGIN SELECT [BusinessEntityID] ,[TerritoryID] ,[SalesQuota] ,[Bonus] ,[CommissionPct] ,[SalesYTD] ,[SalesLastYear] ,[rowguid] ,[ModifiedDate] FROM [Sales].[SalesPerson] WHERE BusinessEntityID<300 END SET NOCOUNT OFF END
複製代碼
複製代碼
EXEC SPSalesPerson @option='select' EXEC SPSalesPerson @option='SalesPerson' DBCC FREEPROCCACHE----清空緩存 ---測試兩個查詢是否都走了緩存計劃 SELECT usecounts,size_in_bytes,cacheobjtype,objtype,TEXT FROM sys.dm_exec_cached_plans cp CROSS APPLY sys.dm_exec_sql_text(cp.plan_handle) st; --執行計劃在第一次執行SQL語句時產生,緩存在內存中,這個緩存的計劃一直可用,直到 SQL Server 從新啓動,或直到它因爲使用率較低而溢出內存。  默認狀況下,存儲過程將返回過程當中每一個語句影響的行數。若是不須要在應用程序中使用該信息(大多數應用程序並不須要),請在存儲過程當中使用 SET NOCOUNT ON 語句以終止該行爲。根據存儲過程當中包含的影響行的語句的數量,這將刪除客戶端和服務器之間的一個或多個往返過程。儘管這不是大問題,但它能夠爲高流量應用程序的性能產生負面影響。
複製代碼

判斷一條查詢是否有值

複製代碼
--如下四個查詢都是判斷鏈接查詢無記錄時所作的操做 ---性能最差消耗0.8秒 SET STATISTICS IO ON SET STATISTICS TIME ON DECLARE @UserType INT ,@Status INT SELECT @UserType=COUNT(c.Id) FROM Customerfo t INNER JOIN Customer c ON c.Id=t.CustomerId WHERE c.customerTel='13400000000' IF(@UserType=0) BEGIN SET @Status = 2 PRINT @Status END SET STATISTICS TIME OFF SET STATISTICS IO OFF go ----性能較好消耗0.08秒  SET STATISTICS IO ON SET STATISTICS TIME ON IF NOT EXISTS(SELECT c.Id FROM Customerfo t INNER JOIN Customer c ON c.Id=t.CustomerId WHERE c.customerTel='13400000000') BEGIN DECLARE @Status int SET @Status = 2 PRINT @Status END SET STATISTICS TIME OFF SET STATISTICS IO OFF go ----性能較好消耗0.08秒  SET STATISTICS IO ON SET STATISTICS TIME ON IF NOT EXISTS(SELECT top 1 c.id FROM Customerfo t INNER JOIN Customer c ON c.Id=t.CustomerId WHERE c.customerTel='13400000000' ORDER BY NEWID() ) BEGIN DECLARE @Status int SET @Status = 2 PRINT @Status END SET STATISTICS TIME OFF SET STATISTICS IO OFF GO ---性能和上面的同樣0.08秒 SET STATISTICS IO ON SET STATISTICS TIME ON IF NOT EXISTS(SELECT 1 FROM Customerfo t INNER JOIN Customer c ON c.Id=t.CustomerId WHERE c.customerTel='13410700660' ) BEGIN DECLARE @Status int SET @Status = 2 PRINT @Status END SET STATISTICS TIME OFF SET STATISTICS IO OFF 這裏說一下SELECT 1,以前由於有程序員誤認爲查詢SELECT 1不管查詢的數據有多少隻返回一個1,其實不是這樣的,和查詢字段是同樣的意思只是有多少記錄就返回多少個1,1也不是查詢的第一個字段。
複製代碼

 理解TRUNCATE和DELETE的區別

複製代碼
---建立表Table1 IF OBJECT_ID('Table1','U') IS NOT NULL DROP TABLE Table1 GO CREATE TABLE Table1 (ID INT NOT NULL, FOID INT NOT NULL) GO --插入測試數據 INSERT INTO Table1 VALUES(1,101),(2,102),(3,103),(4,104) GO ---建立表Table2 IF OBJECT_ID('Table2','U') IS NOT NULL DROP TABLE Table2 GO CREATE TABLE Table2 ( FOID INT NOT NULL) GO
--插入測試數據
INSERT INTO Table2 VALUES(101),(102),(103),(104) GO SELECT * FROM Table1 GO SELECT * FROM Table2 GO 
在Table1表中建立觸發器,當表中的數據被刪除時同時刪除Table2表中對應的FOID
複製代碼
CREATE TRIGGER TG_Table1 ON Table1 AFTER DELETE AS BEGIN DELETE FROM TA FROM Table2 TA INNER JOIN deleted TB ON TA.FOID=TB.FOID END GO
複製代碼
複製代碼
---測試DELETE刪除操做 DELETE FROM Table1 WHERE ID=1 GO ---執行觸發器成功,Table2表中的FOID=101的數據也被刪除 SELECT * FROM Table1 GO SELECT * FROM Table2
複製代碼
複製代碼
---測試TRUNCATE刪除操做 TRUNCATE TABLE Table1 GO ---Table2中的數據沒有被刪除 SELECT * FROM Table1 GO SELECT * FROM Table2
複製代碼

複製代碼
複製代碼
---查看TRUNCATE和DELETE的日誌記錄狀況 CHECKPOINT GO SELECT * FROM fn_dblog(NULL,NULL) GO DELETE FROM Table2 WHERE FOID=102 GO SELECT * FROM fn_dblog(NULL,NULL)
複製代碼

在第四行記錄有一個lop_delete_rows,lcx_heap的刪除操做日誌記錄
複製代碼
----TRUNCATE日誌記錄 CHECKPOINT GO SELECT * FROM fn_dblog(NULL,NULL) GO TRUNCATE TABLE Table2 GO SELECT * FROM fn_dblog(NULL,NULL) GO
複製代碼

 TRUNCATE操做沒有記錄刪除日誌操做

主要的緣由是由於TRUNCATE操做不會激活觸發器,由於TRUNCATE操做不會記錄各行的日誌刪除操做,因此當你須要刪除一張表的數據時你須要考慮是否應該若有記錄日誌刪除操做,而不是根據我的的習慣來操做。

 

事務的理解

複製代碼
---建立表Table1 IF OBJECT_ID('Table1','U') IS NOT NULL DROP TABLE Table1 GO CREATE TABLE Table1 (ID INT NOT NULL PRIMARY KEY, Age INT NOT NULL CHECK(Age>10 AND Age<50)); GO ---建立表Table2 IF OBJECT_ID('Table2','U') IS NOT NULL DROP TABLE Table2 GO CREATE TABLE Table2 ( ID INT NOT NULL) GO
複製代碼

1.簡單的事務提交

複製代碼
BEGIN TRANSACTION INSERT INTO Table1(ID,Age) VALUES(1,20) INSERT INTO Table1(ID,Age) VALUES(2,5) INSERT INTO Table1(ID,Age) VALUES(2,20) INSERT INTO Table1(ID,Age) VALUES(3,20) COMMIT TRANSACTION GO ---第二條記錄沒有執行成功,其餘的都執行成功 SELECT * FROM Table1
因此並非事務中的任意一條語句報錯整個事務都會回滾,其它的可執行成功的語句依然會執行成功並提交。
複製代碼

2.TRY...CATCH

複製代碼
DELETE FROM Table1 BEGIN TRY BEGIN TRANSACTION INSERT INTO Table1(ID,Age) VALUES(1,20) INSERT INTO Table1(ID,Age) VALUES(2,20) INSERT INTO Table1(ID,Age) VALUES(3,20) INSERT INTO Table3 VALUES(1) COMMIT TRANSACTION END TRY BEGIN CATCH ROLLBACK TRANSACTION END CATCH ----從新打開一個回話執行查詢,發現因爲存在對象出錯BEGIN CATCH並無收到執行報錯,且事務一直處於打開狀態,沒有被提交,也沒有執行回滾。 SELECT * FROM Table1 ---若是事務已經提交查詢XACT_STATE()的狀態值是0,或者執行DBCC OPENTRAN SELECT XACT_STATE() DBCC OPENTRAN ---手動執行提交或者回滾操做 ROLLBACK TRANSACTION 
複製代碼
TRY...CATCH不會返回對象錯誤或者字段錯誤等類型的錯誤

想詳細瞭解TRY...CATCH請參考http://www.cnblogs.com/chenmh/articles/4012506.html

 

3.打開XACT_ABORT

複製代碼
SET XACT_ABORT ON BEGIN TRANSACTION INSERT INTO Table1(ID,Age) VALUES(1,20) INSERT INTO Table1(ID,Age) VALUES(2,20) INSERT INTO Table1(ID,Age) VALUES(3,20) INSERT INTO Table3 VALUES(1) COMMIT TRANSACTION SET XACT_ABORT OFF ---事務所有執行回滾操做(對象table3是不存在報錯,可是也回滾全部的提交,跟上面的TRY...CATCH的區別) SELECT * FROM Table1 
複製代碼

複製代碼
---查詢是否有打開事務 SELECT XACT_STATE() DBCC OPENTRAN
未查詢到有打開事務

當 SET XACT_ABORT 爲 ON 時,若是執行 Transact-SQL 語句產生運行時錯誤,則整個事務將終止並回滾。

當 SET XACT_ABORT 爲 OFF 時,有時只回滾產生錯誤的 Transact-SQL 語句,而事務將繼續進行處理。若是錯誤很嚴重,那麼即便 SET XACT_ABORT 爲 OFF,也可能回滾整個事務。OFF 是默認設置。

編譯錯誤(如語法錯誤)不受 SET XACT_ABORT 的影響。

複製代碼

      因此咱們應該根據本身的需求選擇正確的事務。

    

修改字段NOT NULL的過程

複製代碼
在Address表中的有一個Address字段,該字段容許爲NULL,如今須要將其修改成NOT NULL. BEGIN TRANSACTION SET QUOTED_IDENTIFIER ON SET ARITHABORT ON SET NUMERIC_ROUNDABORT OFF SET CONCAT_NULL_YIELDS_NULL ON SET ANSI_NULLS ON SET ANSI_PADDING ON SET ANSI_WARNINGS ON COMMIT BEGIN TRANSACTION GO CREATE TABLE dbo.Tmp_Address ( ID int NOT NULL, Address nvarchar(MAX) NOT NULL ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] GO ALTER TABLE dbo.Tmp_Address SET (LOCK_ESCALATION = TABLE) GO IF EXISTS(SELECT * FROM dbo.Address) EXEC('INSERT INTO dbo.Tmp_Address (ID, Address) SELECT ID, Address FROM dbo.Address WITH (HOLDLOCK TABLOCKX)') GO DROP TABLE dbo.Address GO EXECUTE sp_rename N'dbo.Tmp_Address', N'Address', 'OBJECT' GO COMMIT ---從上面就是一個重置字段爲非空的過程,從上面的語句咱們能夠看到首先要建立一張臨時表在臨時表中Address字段建成了NOT NULL,而後將原表中的數據插入到臨時表當中,最後修改表名,你們能夠想一下若是我要修改的表有幾千萬數據,那這個過程該多麼長並且內存一會兒就會增長不少,因此你們建表的時候就要養成設字段爲NOT NULL --當你要向現有的表中增長一個字段的時候你也要不容許爲NULL,能夠用默認值替代空 Alter Table Address Add MemberType smallint Not Null Default (1)
複製代碼

 

 

總結

後面收集到相似的問題會補充在文章的末尾,文章持續更新中....,歡迎關注討論。

  

若是以爲文章對你們有所幫助,麻煩給個推薦,謝謝!!

 

備註:

    做者:pursuer.chen

    博客:http://www.cnblogs.com/chenmh

本站點全部文章都是原創,歡迎你們轉載;但轉載時必須註明文章來源,且在文章開頭明顯處給明連接,不然保留追究責任的權利。

《歡迎交流討論》

相關文章
相關標籤/搜索