淺析MySQL中的計算列(Generated Column列)與計算字段的介紹與應用-如何讓數據庫中某個字段隨時間自動更新


一、計算列

  MySQL 的 Generated Column 又稱為虛擬列或計算列。Generated Column列的值是在列定義時包含了一個計算表達式計算得到的。

1、定義Generated column列的語法如下:

列名 類型 [GENERATED ALWAYS] AS (expr) [VIRTUAL | STORED]
[NOT NULL | NULL] 
[UNIQUE [KEY]] [[PRIMARY] KEY] [COMMENT 'string']

  (1)AS(expr)用於生成計算列值的表達式。

  (2)VIRTUAL或STORED關鍵字表示是否存儲計算列的值:

  VIRTUAL:列值不存儲,虛擬列不占用存儲空間,默認設置為VIRTUAL。

  STORED:在添加或更新行時計算並存儲列值。存儲列需要存儲空間,並且可以創建索引。

2、Generated column 表達式必須遵循以下規則。如果表達式包含不允許的定義方式,則會發生錯誤。

(1)允許使用文本、內置函數和運算符,但不能使用返回值不確定的函數,比如NOW()。

(2)不允許使用存儲函數和用戶定義函數。

(3)不允許使用存儲過程和函數參數。

(4)不允許使用變量(系統變量、用戶定義變量和存儲程序的局部變量)。

(5)不允許子查詢。

(6)計算列在定義時可以引用其他的計算列,但只能引用表定義中較早出現的列。

(7)可以在計算列上創建索引,但不能在VIRTUAL類型的計算列上創建聚集索引。

3、計算列舉例

(1)表的定義

mysql> create table sales( -> goods_id int primary key, -> goods_name char(20), -> unit_price int, -> quantity int, -> amount int generated always as (unit_price*quantity)); Query OK, 0 rows affected (0.02 sec)

(2)插入數據:amount 自動為 8

mysql> insert into sales(goods_id,goods_name,unit_price,quantity) values(100101,'Apple',2,4); Query OK, 1 row affected (0.00 sec) mysql> select * from sales; +----------+------------+------------+----------+--------+
| goods_id | goods_name | unit_price | quantity | amount |
+----------+------------+------------+----------+--------+
|   100101 | Apple      |          2 |        4 |      8 |
+----------+------------+------------+----------+--------+
1 row in set (0.00 sec)

(3)查看創建表的語句:可見,計算列的默認類型為VIRTUAL。

mysql> show create table sales\G *************************** 1. row ***************************
       Table: sales Create Table: CREATE TABLE `sales` ( `goods_id` int(11) NOT NULL, `goods_name` char(20) DEFAULT NULL, `unit_price` int(11) DEFAULT NULL, `quantity` int(11) DEFAULT NULL, `amount` int(11) GENERATED ALWAYS AS ((`unit_price` * `quantity`)) VIRTUAL, PRIMARY KEY (`goods_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 1 row in set (0.00 sec)

4、計算列區別於需要我們手動或者程序給予賦值的列,它的值來源於該表中其它列的計算值。

  比如,一個表中包含有數量列Number與單價列Price,我們就可以創建計算列金額Amount來表示數量*單價的結果值,創建Amount列后,在程序中需要使用計算金額這個值時,就不用取出Number列與Price列的值后相乘,而是直接取Amount列的值就可以了。  

  那么這個計算列要如何建立呢?先看通過sql的方法創建:

create table table1(   number decimal(18,4),   price money,   Amount as number*price --這里就是計算列
)

  計算列是不需要我們指定數據類型與是否允許為null等信息的,SqlServer會根據情況自動賦予數據類型。在microsoft sql server management studio建創計算列更是簡單。如下圖所示,只要在列屬性中的"計算所得的列規范"-"公式"中填寫計算列的公式就可以了。

  在上面的圖片中我們也看到有"是持久的"這個選項,這個選項有什么用呢?

  計算列如果沒有特殊的設定,它將會是一個虛擬列,也就是這個列實際上是不存在的,只是每次要取這列的值時,sql會按照計算列的公式計算一次,再把結果返回給我們。

  這樣就會存在一些問題,比如,每次計算都會消耗一定的時間,而且也不能在這個列上創建索引。

  那么能不能把計算列的結果存起來,每次取數據的時候直接把結果返回給我們,而不用每次去計算。創建計算列時把"是持久的"這個選項勾起來,就能達到我們的目的了,這時候,計算列就是一個實實在在的列,也可以在該列上創建索引了。

  如果要查看所有已經存在計算列以及該計算列是否為"是持久的",可以利用sys.computed_columns視圖

5、注意:

(1)計算列如果沒有設置為"是持久的",那么它是不可以用來做check,foreign key或not null約束。當然,如果我們在microsoft sql server management studio為計算列設置了check等約束了,sql server會自動將該列設置為"是持久的"。

(2)計算列不可以再次用來作為中一個計算列的一部分。

(3)在觸發器,不可以對計算列進行update判斷,否則會報如下錯誤:列不能在IF UPDATE子句中使用,因為它是計算列。

二、SQL Server 中如何讓數據庫中某一個字段隨時間自動更新?

  今天在sql server論壇看到一個帖子:如何讓數據庫中某一個字段隨時間自動更新?

  那么如何來實現呢?可以用觸發器,那么先要寫個觸發器,但是可能會影響性能。想了想,其實用sql server提供的計算列,就可以輕松實現這個需求。

  例子如下:員工表,有字段:人員id,姓名,人員編碼,人員入職時間,現在希望要增加一個字段顯示工齡,就是在公司工作的時間,如 1.5年。

CREATE TABLE emp ( emp_id INT PRIMARY KEY , emp_name NVARCHAR(10) not null, emp_code VARCHAR(20) not null, hire_date DATE not null ); 

  實現方法就是新增一個計算列:

alter table emp add employment_time as cast(datediff(month,hire_date,GETDATE())*1.0/12 as numeric(8,1));

三、計算字段的應用

1、計算字段

  計算字段存儲在數據庫表里面的數據一般會出現不是應用程序所需要的的數據格式,下面舉3個簡單的例子。

(1)如果想要在一個字段中既要顯示公司的名,又要顯示公司地址,但是這兩個信息一般會包含在不同的列中。

(2)比如物品訂單表存儲物品的價格和數量,但不需要存儲每個物品的總價格,有時候為了打印發票,所以需要物品的總價格。

(3)比如需要根據表數據進行總數,平均數和最大值和最小值或者其他的計算。

  在上述的三個例子中,存儲在表中的數據都不是應用程序所需要的,這個時候我們就需要直接從數據庫中檢索出轉換然后計算或者格式化數據,而不是檢索出數據,然后在客戶機應用程序中重新格式化數據了。

  這個時候就要發揮計算字段的作用了,計算字段不是存儲在數據庫表里面的,而是在運行SELECT語句內創建的,需要注意的是 MySQL 是可以分清哪些是數據庫字段,哪些是計算字段的。

2、拼接字段

  為了更好的說明如何使用計算字段,下面會順便介紹拼接字段,然后連個一起舉例展示。

(1)需求:vendors 表包含供應商名和位置信息。假如要生成一個供應商報表, 需要在供應商的名字中按照 name(location) 這樣的格式列出供應商的位置。此報表需要單個值,而表中數據存儲在兩個列 vend_name 和 vend_ country 中。此外,需要用括號將 vend_country 括起來,這些東西都沒有明確存儲在數據庫表中。我們來看看怎樣編寫返回供應商名和位置的 SELECT語句。

(2)解決辦法是:把兩個列拼接起來。在MySQL的SELECT語句中,可使用 Concat() 函數來拼接兩個列。Concat()拼接串,即把多個串連接起來形成一個較長的串。看下面的sql語句和執行結果。

  分析一下上面的 sql 語句的,首先 Concat() 需要一個或多個指定的串,各個串之間用逗號分隔。 上面的SELECT語句連接以下4個元素:分別是,存儲在vend_name列中的名字;包含一個空格和一個左圓括號的串;存儲在vend_country列中的國家;包含一個右圓括號的串。

  從上述輸出中可以看到,SELECT語句返回包含上述4個元素的單個列 (計算字段)。這個就是拼接字段和計算字段的使用方法。

3、執行算術計算

(1)需求:orders 表包含收到的所有訂單,orderitems 表包含每個訂單的各項物品,下面要查出訂單號為20005的所有物品。

  先查詢訂單號為20005的所有物品

  item_price列包含訂單中每項物品的單價。如下匯總物品的價格(單價乘以訂購數量)

  從輸出的結果我們可以看出,expanded_price 列為一個計算字段展示,此列的計算值為 quantity*item_price,客戶機可以直接使用這個計算出來的結果,而不是查詢出數量和價格然后在客戶機里面重新定義重新計算。

  內容捯飭當然客戶機是完全可以進行這些計算和格式化數據的,但是一般來說,在數據庫服務器上面完成這些操作要比在客戶機中完成要快得多,因為DBMS是設計快速有效地完成這種處理的。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM