本節將要介紹使用 T-SQL 來建立表和定義數據完整性的基礎內容。你能夠在 SQL Server 環境中隨意運行本節包括的代碼例子。數據庫
在閱讀建表語句以前,應該記住:表是屬於架構,而架構又是屬於數據庫的。例子中使用的數據庫名稱是 testdb ,使用的架構名稱是 dbo 。要在你的 SQL Server 環境中建立一個名爲 testdb 的數據庫,能夠運行如下代碼:架構
IF DB_ID('testdb') IS NULL CREATE DATABASE testdb;
若是還不存在名爲 testdb 的數據庫,這段代碼就會建立一個新的。 DB_ID 函數接受一個數據庫名稱做爲輸入參數,返回它的內部數據庫 ID。若是輸入名稱指定的數據庫不存在,這個函數將返回 NULL 。這是一種檢查數據庫是否存在的簡單方法。注意:在這個簡單的 CREATE DATABASE 語句中,採用了默認的文件設置(例如,區域和初始大小)。在生產環境中,一般應該顯示指定全部須要的數據庫和文件的設置。不過對於咱們如今的目的來講,默認設置就夠用了。函數
在例子中使用的架構是 dbo ,在每一個數據庫中都會自動建立這個架構。當用戶沒有顯式指定默認架構時,就會將這個 dbo 做爲默認架構。spa
如下代碼在 testdb 數據庫中建立一個名爲 Employees 的表:code
USE testdb; IF OBJECT_ID('dbo.Employees', 'U') IS NOT NULL DROP TABLE dbo.Employees; CREATE TABLE dbo.Employees ( empid INT NOT NULL, firstname VARCHAR (30) NOT NULL, lastname VARCHAR (30) NOT NULL, hiredate DATE NOT NULL, mgrid INT NULL, ssn VARCHAR (20) NOT NULL, salary money NOT NULL );
USE 語句將當前的數據庫上下文切換爲 testdb 。在建立對象的腳本中加入 USE 語句,它的重要做用是確保要在正確的數據庫中建立對象。對象
IF 語句調用 OBJECT_ID 函數來檢查當前數據庫中是否存在 Employees 表。 OBJECT_ID 函數接受一個對象名稱和類型做爲它的輸入參數。這裏,類型 'U' 表明用戶表。若是匹配給定輸入名稱和類型的對象存在,這個函數就返回內部的對象 ID,不然返回 NULL 。若是該函數返回 NULL ,就能夠知道檢查的數據庫對象是不存在的。在這個例子中,若是 Employees 表已經存在,代碼就先刪除( DROP )這個表,接着再建立一個新的。固然,也能夠選擇不一樣的處理方法,例如,當 Employees 表已經存在時,能夠簡單地不建立這個對象。blog
CREATE TABLE 語句負責定義前面提到的關係的主體。這個語句中先指定表的名稱,接着在圓括號中定義它的各個屬性(列)。索引
注意表名稱使用了前面推薦的由兩部分組成的名稱 dbo.Employees 。若是省略了架構名稱,SQL Server 將使用與運行這段代碼的數據庫用戶相關聯的默認架構。ci
對於表的每一個屬性,須要指定它的屬性名稱、數據類型和是否容許 NULL 數據值(NULLability)。字符串
在 Employees 表中, empid (員工 ID)和 mgrid (經理 ID)定義爲 INT (4 字節的整數類型); firstname 、 lastname 和 ssn (社會保險號,social security number)定義爲 VARCHAR (可變長度的字符串類型,指定最多支持的字符個數); hiredate 定義爲 DATE , salary 定義爲 MONEY 。注意: DATE 數據類型是 SQL Server 2008 新增長的。若是使用的是這一產品的早期版本,則應該使用 DATETIME 或 SMALLDATETIME 數據類型。
若是不顯式指定一個列是否容許 NULL 值,SQL Server 則採用默認值。ANSI 規定:若是不指定一個列是否容許 NULL 值,則假設應該是 NULL (容許 NULL 值)。但 SQL Server 提供了一些設置能夠改變這一默認行爲。在這裏強烈推薦在這種狀況下要顯式指定設置,不要依賴其默認值。並且,也強烈推薦將列定義爲 NOT NULL ,除非有明顯的緣由而必需要支持 NULL 。即便認爲一個列不容許 NULL 值,但沒有用 NOT NULL 約束加以限制時, NULL 值仍然能夠插入到這個列中。在 Employees 表中,除了 mgrid 列,其它全部列都定義爲 NOT NULL 。 mgrid 屬性爲 NULL 值表示員工沒有經理,例如企業 CEO 這種狀況。
前面說過,關係模型帶來的最大優勢之一就是模型自己集成了數據完整性。做爲模型的一部分而實施的數據完整性(也就是做爲表定義的一部分)成爲聲明式(declarative)數據完整性。用代碼來實施數據的完整性(例如用存儲過程或觸發器)成爲過程式(procedural)數據完整性。
爲屬性選擇的數據類型和是否容許爲 NULL 值,甚至數據模型自己都是聲明式數據完整性約束的例子。本節主要介紹聲明式約束的其它例子,包括主鍵、惟一約束( UNIQUE )、外鍵、檢查約束( CHECK ),以及默認( DEFAULT )約束。當用 CREATE TABLE 語句建立表時,能夠同時定義這些約束;或者在已經建立好表以後,用 ALTER TABLE 語句增長這些約束。除了 DEFAULT 約束之外,其它全部約束均可以定義爲組合約束(即基於一個或多個約束)。
主鍵約束用來實施行的惟一約束,同時不容許約束屬性取 NULL 值。約束屬性中每一組惟一的值在表中只能出現一次,換句話說,表內的每行數據能夠被惟一肯定。若是視圖在容許 NULL 值的列上定義主鍵約束,RDBMS 會拒絕。每一個表只能定義一個主鍵。
下面之前面建立的 Employees 表爲例,在它的 empid 列上定義一個主鍵約束:
ALTER TABLE dbo.Employees ADD CONSTRAINT PK_Employees PRIMARY KEY(empid);
定義好主鍵之後,就能夠保證全部的 empid 值將是惟一而肯定的。若是插入或更新一行違反約束的數據,RDBMS 就會拒絕操做,生成一個報錯。
爲了實施邏輯主鍵約束的惟一約束,SQL Server 將在幕後建立一個惟一的索引(unique index)。惟一索引是 SQL Server 爲了實施惟一約束而採用的一種物理機制。也能夠用索引(不必定是惟一索引)來加速查詢的處理,避免對整個表進行沒必要要的掃描(相似於圖書的索引)。
惟一約束用來保證數據行的一個列(或一組列)的數據惟一,能夠在數據庫中實現關係模型的替換鍵(alternate key)的概念。與主鍵不一樣的是,在同一個表中能夠定義多個惟一約束。此外,惟一約束也不限於只定義在 NOT NULL 列上。ANSI SQL 支持兩種類型的惟一約束,一種是隻容許在惟一約束列中有一個列值能夠爲 NULL ,另外一種則容許多個 NULL 值列。SQL Server 只實現了前者。
如下代碼在 Employees 表中定義了 ssn 列上的一個惟一約束:
ALTER TABLE dbo.Employees ADD CONSTRAINT UNQ_Employees_ssn UNIQUE(ssn);
和主鍵約束同樣,SQL Server 也在幕後建立一個惟一索引,做爲實施邏輯惟一約束的物理機制。
外鍵約束用於實施引用完整性。這種約束在引用表(referencing table)的一組屬性上進行定義,並指向被引用表(referenced table)中的一組候選鍵(主鍵或惟一約束)。注意:引用表和被引用表多是同一張表。外鍵的目的是爲了將外鍵列容許的值域限制爲被引用列中現有的值。
如下代碼建立了一個名爲 Orders 的表,其主鍵定義在 orderid 列上:
IF OBJECT_ID('dbo.orders', 'U') IS NOT NULL DROP TABLE dbo.orders ; CREATE TABLE dbo.orders ( orderid INT NOT NULL, empid INT NOT NULL, custid VARCHAR (10) NOT NULL, orderts DATETIME NOT NULL, qty INT NOT NULL, CONSTRAINT PK_Orders PRIMARY KEY (orderid) );
若是如今想實施一個完整性規則,將 Orders 表的 empid 列支持的值域限制爲現有的 Employees 表中 empid 列的值。爲此,要在 Orders 表的 empid 列上定義一個外鍵約束,讓它指向 Employees 表的 empid 列,以下所示:
ALTER TABLE dbo.orders ADD CONSTRAINT FK_Orders_Employees FOREIGN KEY (empid) REFERENCES dbo.Employees (empid);
相似的,若是想限制 Employees 表的 mgrid 列支持的值域爲當前表中已存在的那些 empid 列的值,能夠增長如下外鍵約束:
ALTER TABLE dbo.Employees ADD CONSTRAINT FK_Employees_Employees FOREIGN KEY (empid) REFERENCES dbo.Employees (empid);
前面兩個例子演示了外鍵的基本定義,它們實施的引用操做稱爲「禁止操做(no action)」。禁止操做的含義是:當試圖刪除被引用表中的行,或更新被引用的候選鍵時,若是在引用表中存在相關的行,則此操做不能執行。例如,若是視圖從 Employees 表中刪除一個員工數據行,而 Orders 表中同時還存在與這個員工相關的訂單數據行,RDBMS 將拒絕執行這樣的操做,並生成報錯信息。
能夠定義具備級聯操做的外鍵——爲了當在引用表中存在相關數據行時能夠刪除被引用表中的數據行或更新被引用候選鍵屬性。能夠在外鍵定義中將 ON DELETE 和 ON UPDATE 選項定義爲 CASCADE 、 SET DEFAULT 和 SET NULL 之類的操做。 CASCADE 的含義是:操做(刪除或更新)將被級聯到引用表中相關的行。例如, ON DELETE CASCADE 意味着當從被引用表中刪除一行時,RDBMS 也將從引用表中刪除相關的行。 SET DEFAULT 和 SET NULL 意味着會把相關行的外鍵屬性分別設置爲列的默認值或 NULL 值。
檢查約束用於定義在表中輸入或修改一行數據以前必須知足一個謂詞。例如,如下的檢查約束能夠保證 Employees 表中的 salary 列只支持正數:
ALTER TABLE dbo.Employees ADD CONSTRAINT CHK_Employees_salary CHECK(salary > 0);
若是試圖用非正數的 salary 值插入或更新數據行,RDBMS 將拒絕這樣的操做。注意:當謂詞計算結果爲 FALSE 時,檢查約束將拒絕插入或更新數據行的操做。當謂詞計算結果爲 TRUE 或 UNKNOWN 時,RDBMS 將會接受對數據行的修改。例如, salary 爲 -1000 將被拒絕,而 salary 爲 1000 和 NULL 均可以被接受。
當增長 CHECK 和 FOREIGN KEY 約束時,能夠指定一個 WITH NOCHECK 選項,告訴 RDBMS 沒必要對現有的數據進行約束檢查。一般認爲這是一種很差的作法,由於這樣不能保證數據的一致性。
默認約束與特定的屬性關聯。當插入一行 數據是,若是沒有爲屬性顯示指定明確的值,就能夠用一個表達式做爲其默認值。例如,如下代碼爲 orderts 屬性定義了一個默認約束(表示訂單的時間戳):
ALTER TABLE dbo.Orders ADD CONSTRAINT CHK_Orders_orderts DEFAULT(CURRENT_TIMESTAMP) FOR orderts;
默認表達式會調用 CURRENT_TIMESTAMP 函數,由它返回當前的日期和時間值。在定義好默認表達式之後,當在 Orders 表插入一行數據,並且沒有顯示指定 orderts 屬性值時,SQL Server 將把這個屬性值設置爲 CURRENT_TIMESTAMP 函數返回的值。