# 6. 枚舉類型
#### 1. 傳統方式
有很多數據或資源是這樣,具有一個類型或狀態屬性,比如,訂單有pending,approve狀態,博文有草稿(draft),出版(published)的狀態,而一般來存這種數據可以選擇存成字符串(string),或整型(integer)。建議如果是中文的字符串就不要存進數據庫了,不存可以避免很多問題。而大多數人是存整形,就是數字1、2、3之類,比如,1代表draft,2代表published,這樣可以節約空間啊,整型肯定比字符串占用的空間小些,如果要讀出1或2代表的數據,用一個常量hash來匹配就好了,比如`STATUS_TEXT = { 1: '待處理', 2: '操盤中', 3: '已完結' }`。
而Rails的activerecord也支持enum方法,來支持更多的判斷等操作。比如
```
class Conversation < ActiveRecord::Base
enum status: [ :active, :archived ]
end
# conversation.update! status: 0
conversation.active!
conversation.active? # => true
conversation.status # => "active"
# 返回所有類型
Conversation.statuses # => { "active" => 0, "archived" => 1 }
```
#### 2. PostgreSQL的枚舉類型
PostgreSQL官方文檔[enum](http://www.postgresql.org/docs/9.1/static/datatype-enum.html)介紹了枚舉類型和它的操作。
創建枚舉類型。
```
CREATE TYPE mood AS ENUM ('sad', 'ok', 'happy');
```
使用只要指定TYPE的名稱即可。
```
CREATE TABLE person (
name text,
current_mood mood
);
INSERT INTO person VALUES ('Moe', 'happy');
SELECT * FROM person WHERE current_mood = 'happy';
name | current_mood
------+--------------
Moe | happy
(1 row)
```
[functions-enum](http://www.postgresql.org/docs/9.4/static/functions-enum.html)這里有enum所有支持的函數。
#### 2. 在Rails中的使用
添加枚舉的列。
```
# 20151009022320_add_status_to_articles.rb
class AddStatusToArticles < ActiveRecord::Migration
def up
execute <<-SQL
CREATE TYPE article_status AS ENUM ('draft', 'published');
SQL
add_column :articles, :status, index: true
end
def down
execute <<-SQL
DROP TYPE article_status;
SQL
remove_column :articles, :status
end
end
```
在article.rb中定義enum。
```
# article.rb
class Article < ActiveRecord::Base
enum status: {
draft: 'draft',
published: 'published'
}
end
```
假如之后有另外的值要添加的話,那也簡單。用`ALTER TYPE`命令即可。
```
ALTER TYPE enum_type ADD VALUE 'new_value'; -- appends to list
ALTER TYPE enum_type ADD VALUE 'new_value' BEFORE 'old_value';
ALTER TYPE enum_type ADD VALUE 'new_value' AFTER 'old_value';
```
用Rails可以這樣做。
```
disable_ddl_transaction!
def up
execute <<-SQL
ALTER TYPE article_status ADD VALUE IF NOT EXISTS 'archived' AFTER 'published';
SQL
end
```
查看數據庫的所有枚舉類型可以這樣。
```
SELECT n.nspname AS enum_schema,
t.typname AS enum_name,
e.enumlabel AS enum_value
FROM pg_type t
JOIN pg_enum e ON t.oid = e.enumtypid
JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace
```
完結。