Sql Server提供的計算列是一個虛擬的列,通常情況下該列的值是由表中的其它列計算得出的。默認情況下,它不占用磁盤容量,因為這些計算列都是根據指定的表達式動態計算出來的,只有查詢的時候才會進行計算出來。然而,如果使用了persisted關鍵字的計算列,該關鍵詞會將表達式的計算結果寫入到磁盤中,並進行持久化存儲。同時,也可以在計算列上建立索引,約束,或外鍵等。
場景舉例:
a. 提高JSON數據查詢的效率。假如jsontxt字段中存儲着一系列鍵值對,如果要查詢某一個鍵對應的值,那么就要使用JSON_VALUE函數 JSON_VALUE(jsontxt,'$."your key"') 。當你每一次用JSON_VALUE函數時,都會把整個jsontxt字段加載到內存中,然后再找到 your key 的值。當jsontxt數據增大后,這個查詢將會逐漸變慢。
b. 承擔表中字段的計算任務。比如:一個員工表[employees],每一個員工都有一個出生日期[birthday]字段,那么年齡字段[age]的值就可以被動態計算出來了,計算表達式: datediff(year,birthday,getdate()) 。再例如訂單表,訂單的支付金額可以根據產品價格,產品數量,運費,優惠金額,以及 稅費 等字段計算得出。
你可以通過SqlServer Management Studio的UI界面操作來指定計算列,也可以通過Transact-SQL來指定計算列。
在Sql Server Management Studio中, 右鍵列 -》modify -》 新建列 -》Computed Column Specification 中來指定計算列。
通過Transact-SQL 來指定計算列,格式為: 列名 as 表達式 。
-- 在創建表的時候指定為計算列 create table Employees( birthday datetime, age as datediff(year,birthday,getdate())); -- 在已經創建的表上添加計算列 create table Employees(birthday datetime); alter table Employees add age as datediff(year,birthday,getdate());
若要指定計算列為持久化存儲(Persisted), 那么表達式中的計算結果必需是確定性的。比如上面的Age使用了getdate() 函數,這使得Age變成不確定性的,因此不能持久化Age,以及不能在Age上建立索引。
指定計算列為持久化存儲只需要在后面加上persisted關鍵字即可,例如:
-- 在創建表的時候指定計算列 create table Products( id INT NOT NULL IDENTITY PRIMARY KEY, name nvarchar(50) not null, jsontxt nvarchar(4000) not null, [side effect] as JSON_VALUE(jsontxt,'$."side effect"') persisted ); -- 在已經創建的表上添加計算列 create table Products( id INT NOT NULL IDENTITY PRIMARY KEY, name nvarchar(50) not null, jsontxt nvarchar(4000) not null ); alter table Products add [side effect] as JSON_VALUE(jsontxt,'$."side effect"') persisted;
表Products中的jsontxt字段存儲的是JSON格式的鍵值對,是產品的詳細參數,side effect是產品中的某一個參數。為了方便管理,才將這些參數整體封裝在jsontxt字段中。
-- 插入測試數據 insert into Products(name,jsontxt) values( 'Pfizer–BioNTech COVID-19 vaccine', '{ "storage":"10℃", "type":"vaccine", "target":"Coronavirus", "side effect":"Tiredness,Headache" }');
計算列除了不能執行Insert, Update外,其余的和普通列一樣,直接使用計算列的列名即可:
-- 查詢數據 select [side effect] from Products where [side effect] like '%headache%'; -- output: Tiredness,Headache -- 更新jsontxt中的值 update Products set jsontxt = JSON_MODIFY(jsontxt,'$."side effect"', 'Tiredness,Headache,Muscle pain,Chills,Fever'); -- 再次查詢數據 select [side effect] from Products where [side effect] like '%headache%'; -- output: Tiredness,Headache,Muscle pain,Chills,Fever
注意:
- 計算列不能指定INSERT, 和 UPDATE語句。
- persisted關鍵字不能用於含有不確定性的計算列中。
- 只有指定了persisted關鍵字的計算列,才會持久化存儲。如果沒指定persisted關鍵字,那么每次查詢計算列都會重新計算一遍表達式。
- 在創建計算列的時候,我們通常需要進行一些操作以便生成我們期望的值。這個過程中,常常需要用到SQL Server的內置函數,但並不是所有的SQL Server內置函數都是 確定性的(Deterministic),只有全是 確定性類型(Deterministic) 函數生成的動態計算列,才可以進行持久化存儲。SQL Server數據庫中所有Deterministic的內置函數列表。
參考文獻: