在PostgreSQL中,數(shù)據(jù)就是存放在數(shù)據(jù)表中,在一張數(shù)據(jù)表中,每一列就是一個(gè)字段,即表示哪種類型的數(shù)據(jù)。每一行就是不同的類型的數(shù)據(jù)。對(duì)數(shù)據(jù)表的操作也是:創(chuàng)建、修改和刪除。
創(chuàng)建表
創(chuàng)建表的基本命令格式如下:
CREATE TABLE table_name (
field1 datatype1,
field2 datatype2,
....
);
格式就是在括號(hào)中一個(gè)字段名和一個(gè)字段類型,字段和字段類型之間用空格隔開。不同字段之間用逗號(hào)隔開。示例如下:
postgres=# CREATE TABLE testdb1 (id int, comments varchar(20));
CREATE TABLE
postgres=# \d testdb1;
Table "public.testdb1"
Column | Type | Modifiers
----------+-----------------------+-----------
id | integer |
comments | character varying(20) |
上面的示例中就創(chuàng)建了一個(gè)普通的表,表中沒有任何約束。約束指的是對(duì)表中的字段進(jìn)行一定的限制,或?qū)蓚€(gè)不同的表之間的字段進(jìn)行限制。約束的類型主要包括:
- 主鍵約束,分為單字段主鍵和多字段主鍵,后者也被稱為復(fù)合主鍵。
- 外鍵約束,表中的字段和另外一張表里的字段有對(duì)應(yīng)關(guān)系,更新一張表時(shí)必須檢查另外一張表
- 唯一約束,有這個(gè)約束的字段中的值只能出現(xiàn)一次。一般用于具有唯一性的數(shù)值。
- 非空約束,即這個(gè)字段的值不能是null
- 檢查約束,即Check約束,用于定義某些字段的值必須滿足某些要求。
下面幾個(gè)示例中分別顯示了定義表的時(shí)候?qū)Ρ淼哪承┳侄芜M(jìn)行約束。
主鍵約束、唯一約束和非空約束
#上面的表中,我們創(chuàng)建了一個(gè)兩個(gè)字段的表testdb1,且表中沒有任何約束,如下所示:
postgres=# \d testdb1
Table "public.testdb1"
Column | Type | Modifiers
----------+-----------------------+-----------
id | integer |
comments | character varying(20) |
將這個(gè)表的id字段設(shè)置為表的主鍵,可以看到id字段也自動(dòng)變成了非空字段(not null)
postgres=# alter table testdb1 add primary key(id);
ALTER TABLE
postgres=# \d testdb1
Table "public.testdb1"
Column | Type | Modifiers
----------+-----------------------+-----------
id | integer | not null
comments | character varying(20) |
Indexes:
"testdb1_pkey" PRIMARY KEY, btree (id)
嘗試往表中插入數(shù)據(jù)
postgres=# insert into testdb1 values(1, 'test');
INSERT 0 1
postgres=# insert into testdb1 values(2, 'not all');
INSERT 0 1
postgres=# insert into testdb1 values(2, 'not you');
ERROR: duplicate key value violates unique constraint "testdb1_pkey"
DETAIL: Key (id)=(2) already exists.
postgres=# select * from testdb1;
id | comments
----+----------
1 | test
2 | not all
(2 rows)
上面進(jìn)行了3次插入操作,前兩次插入成功,第三次插入失敗。第三次插入的數(shù)據(jù)中id=2,和第二次插入的數(shù)據(jù)中的id相同,說明主鍵具有唯一性。
通過字段名進(jìn)行插入,如下所示:
postgres=# insert into testdb1(comments) values('not you');
ERROR: null value in column "id" violates not-null constraint
DETAIL: Failing row contains (null, not you).
發(fā)現(xiàn)插入出錯(cuò),說明主鍵字段id不會(huì)自增到下一個(gè)值,說明主鍵沒有自增特性
同時(shí)也看到了非空約束的作用,就是限制這個(gè)字段的值不能是一個(gè)空值。
#刪除主鍵約束
postgres=# alter table testdb1 drop constraint testdb1_pkey;
ALTER TABLE
postgres=# \d testdb1;
Table "public.testdb1"
Column | Type | Modifiers
----------+-----------------------+-----------
id | integer | not null
comments | character varying(20) |
從上面的示例中講解了主鍵約束的添加、數(shù)值插入、以及刪除操作。從四個(gè)簡(jiǎn)短的小示例中我們看到主鍵約束有以下特性:
- 非空
- 唯一性
- 不會(huì)自動(dòng)增加值
也看到了唯一性約束和非空約束的作用:
- 唯一約束的字段值不能重復(fù)
- 非空約束的字段對(duì)應(yīng)的值不能是一個(gè)空值
如果沒有定義主鍵,而是想直接定義另外一個(gè)鍵的類型為唯一約束,可以使用關(guān)鍵字UNIQUE,示例如下:
postgres=# alter table testdb1 add unique(comments);
ALTER TABLE
postgres=# \d testdb1;
Table "public.testdb1"
Column | Type | Modifiers
----------+-----------------------+-----------
id | integer | not null
comments | character varying(20) |
Indexes:
"testdb1_comments_key" UNIQUE CONSTRAINT, btree (comments)
postgres=# select * from testdb1;
id | comments
----+----------
1 | test
2 | not all
(2 rows)
postgres=# insert into testdb1 values(3, 'test');
ERROR: duplicate key value violates unique constraint "testdb1_comments_key"
DETAIL: Key (comments)=(test) already exists.
刪除唯一性約束
postgres=# alter table testdb1 drop constraint testdb1_comments_key;
ALTER TABLE
postgres=# \d testdb1;
Table "public.testdb1"
Column | Type | Modifiers
----------+-----------------------+-----------
id | integer | not null
comments | character varying(20) |
在上面示例中,我們將comments字段設(shè)置為UNIQE約束,然后做了一次插入操作,插入的comments值和id=1時(shí)的值相同,此時(shí)發(fā)生了報(bào)錯(cuò)。說明UNIQE約束生效。
而單獨(dú)設(shè)置某個(gè)字段為not null類型字段,則需要使用另外一種命令格式:
#在comments字段上添加非空約束
postgres=# alter table testdb1 alter comments set not null;
ALTER TABLE
postgres=# \d testdb1;
Table "public.testdb1"
Column | Type | Modifiers
----------+-----------------------+-----------
id | integer | not null
comments | character varying(20) | not null
Indexes:
"testdb1_comments_key" UNIQUE CONSTRAINT, btree (comments)
# 取消comments字段的非空約束
postgres=# alter table testdb1 alter comments drop not null;
ALTER TABLE
postgres=# \d testdb1;
Table "public.testdb1"
Column | Type | Modifiers
----------+-----------------------+-----------
id | integer | not null
comments | character varying(20) |
Indexes:
"testdb1_comments_key" UNIQUE CONSTRAINT, btree (comments)
從上面兩個(gè)示例中我們還可以總結(jié)出一點(diǎn),主鍵約束和唯一約束,是另外附加給字段的約束類型,因此會(huì)顯示在表信息下面。而非空約束則是字段內(nèi)在的屬性,會(huì)和字段一起顯示。因此會(huì)使用不同的方式來添加和刪除,主鍵約束和唯一約束通過下面的命令來添加和刪除
alter table table_name add constraint_name (field_name); #添加主鍵約束或唯一約束
alter table table_name drop constraint constraint_name; #刪除主鍵約束或唯一約束
而非空約束則通過修改字段屬性來添加和刪除非空約束,如下所示:
alter table tablename alter field_name set not null; #添加非空約束
alter table tablename alter field_name drop not null; #刪除非空約束
外鍵約束
外鍵約束也是一種外部約束,可以使用主鍵約束和唯一約束相同的命令來添加,唯一不同的就是語法,同時(shí)要求關(guān)聯(lián)的字段必須是另外一張表的主鍵。示例如下:
還是前面的testdb1表格,我們新增一個(gè)字段parent_id,要求將這個(gè)字段和一個(gè)新的testdb2表格的id字段進(jìn)行關(guān)聯(lián):
postgres=# \d testdb1;
Table "public.testdb1"
Column | Type | Modifiers
-----------+-----------------------+-----------
id | integer | not null
comments | character varying(20) |
# 增加一個(gè)字段parent_id,命令如下:
postgres=# alter table testdb1 add column parent_id int;
ALTER TABLE
postgres=# \d testdb1;
Table "public.testdb1"
Column | Type | Modifiers
-----------+-----------------------+-----------
id | integer | not null
comments | character varying(20) |
parent_id | integer |
#字段添加完成后,查看新表testdb2,
postgres=# \d testdb2;
Table "public.testdb2"
Column | Type | Modifiers
--------+-----------------------+-----------
id | integer | not null
info | character varying(50) |
Indexes:
"testdb2_pkey" PRIMARY KEY, btree (id)
#字段id是表testdb2的主鍵,在testdb1的parent_id字段上增加外鍵約束,命令如下:
postgres=# alter table testdb1 add foreign key(parent_id) references testdb2(id);
ALTER TABLE
postgres=# \d testdb1;
Table "public.testdb1"
Column | Type | Modifiers
-----------+-----------------------+-----------
id | integer | not null
comments | character varying(20) |
parent_id | integer |
Foreign-key constraints:
"testdb1_parent_id_fkey" FOREIGN KEY (parent_id) REFERENCES testdb2(id)
## 刪除外鍵約束
postgres=# alter table testdb1 drop constraint testdb1_parent_id_fkey;
ALTER TABLE
postgres=# \d testdb1;
Table "public.testdb1"
Column | Type | Modifiers
-----------+-----------------------+-----------
id | integer | not null
comments | character varying(20) |
parent_id | integer |
#可以看到外鍵約束已經(jīng)刪除。
檢查約束
檢查約束一般是用來限制字段的類型或數(shù)值范圍的,也是一種外部約束,添加和刪除的命令和其他幾種外部約束相同,示例如下:
#添加檢查約束,限制parent_id字段數(shù)值范圍是3~10之間
postgres=# alter table testdb1 add check (parent_id > 3 and parent_id < 10);
ALTER TABLE
postgres=# \d testdb1;
Table "public.testdb1"
Column | Type | Modifiers
-----------+-----------------------+-----------
id | integer | not null
comments | character varying(20) |
parent_id | integer |
Check constraints:
"testdb1_parent_id_check" CHECK (parent_id > 3 AND parent_id < 10)
postgres=# \d testdb1;
Table "public.testdb1"
Column | Type | Modifiers
-----------+-----------------------+-----------
id | integer | not null
comments | character varying(20) |
parent_id | integer |
Check constraints:
"testdb1_parent_id_check" CHECK (parent_id > 3 AND parent_id < 10)
#刪除檢查約束,直接根據(jù)約束名稱刪除。
postgres=# alter table testdb1 drop constraint testdb1_parent_id_check;
ALTER TABLE
postgres=# \d testdb1;
Table "public.testdb1"
Column | Type | Modifiers
-----------+-----------------------+-----------
id | integer | not null
comments | character varying(20) |
parent_id | integer |
修改表
修改表的操作主要有兩種,第一種是修改字段的屬性,第二種是修改字段對(duì)應(yīng)的值。字段的屬性包括:字段類型、字段默認(rèn)值、字段約束等。字段約束的添加和修改我們?cè)谏厦鎰?chuàng)建表的部分已經(jīng)講過,這一部分我們就講解一下字段類型和字段默認(rèn)值的修改。
修改字段類型
基本命令格式如下:
alter table tablename alter field_name type tyepname;
修改字段類型這個(gè)操作要求修改前后的字段類型必須是能夠轉(zhuǎn)換的類型,同時(shí),進(jìn)行類型轉(zhuǎn)換的時(shí)候,會(huì)存在數(shù)據(jù)精度丟失等問題,因此在前期進(jìn)行數(shù)據(jù)庫設(shè)計(jì)的時(shí)候,對(duì)于字段的類型一定要考慮清楚,因?yàn)橐坏┍碇写嫒肓藬?shù)據(jù),再進(jìn)行類型修改的操作是非常危險(xiǎn)的。示例如下:
postgres=# \d testdb1;
Table "public.testdb1"
Column | Type | Modifiers
-----------+-----------------------+-----------
id | integer | not null
comments | character varying(20) |
parent_id | integer |
postgres=# select * from testdb1;
id | comments | parent_id
----+----------+-----------
1 | test |
2 | not all |
(2 rows)
postgres=# alter table testdb1 alter parent_id type varchar(5);
ALTER TABLE
postgres=# \d testdb1;
Table "public.testdb1"
Column | Type | Modifiers
-----------+-----------------------+-----------
id | integer | not null
comments | character varying(20) |
parent_id | character varying(5) |
上面的示例中直接將testdb1表中的parent_id字段類型從int類型修改為varchar(5)類型,字符類型和整數(shù)類型存在轉(zhuǎn)換關(guān)系,且parent_id字段在表中沒有任何值,因此可以直接轉(zhuǎn)換。
我們?cè)诒碇胁迦胍粋€(gè)值,然后再嘗試將parent_id轉(zhuǎn)換為int類型,如下所示:
postgres=# insert into testdb1 values(3,'no poll', 't');
INSERT 0 1
postgres=# select * from testdb1;
id | comments | parent_id
----+----------+-----------
1 | test |
2 | not all |
3 | no poll | t
(3 rows)
postgres=# alter table testdb1 alter parent_id type int;
ERROR: column "parent_id" cannot be cast automatically to type integer
HINT: You might need to specify "USING parent_id::integer".
此時(shí)我們就看到了系統(tǒng)給出的提示,需要使用USING parent_id::integer這樣的關(guān)鍵字來強(qiáng)制轉(zhuǎn)換。我們來嘗試一下,然后看表中的數(shù)值變化:
postgres=# alter table testdb1 alter COLUMN parent_id type int USING parent_id::integer;
ERROR: invalid input syntax for integer: "t"
但是這個(gè)時(shí)候發(fā)現(xiàn),它給出提示,t是對(duì)于integer類型來說是一個(gè)錯(cuò)誤的語法,說明我們剛剛插入的值是不能進(jìn)行varchar到integer的轉(zhuǎn)換的,我們將這個(gè)值刪去,然后插入另外一個(gè)字符類型的數(shù)字,再嘗試轉(zhuǎn)換類型看看。
postgres=# delete from testdb1 where id=3;
DELETE 1
postgres=# insert into testdb1 values(3,'test again', ' 42');
INSERT 0 1
postgres=# select * from testdb1;
id | comments | parent_id
----+------------+-----------
1 | test |
2 | not all |
3 | test again | 42
(3 rows)
postgres=# alter table testdb1 alter column parent_id type int using parent_id::integer;
ALTER TABLE
postgres=# select * from testdb1;
id | comments | parent_id
----+------------+-----------
1 | test |
2 | not all |
3 | test again | 42
(3 rows)
我們發(fā)現(xiàn)這個(gè)時(shí)候轉(zhuǎn)換成功了,這兩個(gè)小例子說明,要轉(zhuǎn)換類型的字段,轉(zhuǎn)換前后的類型必須是可以轉(zhuǎn)換的,否則會(huì)出錯(cuò)。而至于精度丟失的問題,例如從小數(shù)類型轉(zhuǎn)換成整數(shù)類型,必然會(huì)丟失小數(shù)部分。這個(gè)就留給讀者自己進(jìn)行實(shí)驗(yàn)了。
修改字段默認(rèn)值
給表中插入數(shù)據(jù)的時(shí)候,如果這個(gè)字段沒有給出值,則會(huì)使用默認(rèn)值,對(duì)于某些設(shè)置來說還是非常方便的。默認(rèn)值也屬于字段的內(nèi)在屬性,可以使用和添加非空約束同樣的命令來修改,示例如下:
postgres=# alter table testdb1 alter COLUMN comments set default 'test';
ALTER TABLE
在上面的命令中,我將comments字段的默認(rèn)值設(shè)置為'test',下面我們嘗試往testdb1表中再插入數(shù)值,插入的時(shí)候要注意,此時(shí)如果給擁有默認(rèn)值的字段一個(gè)新值,則使用新值,如果不給新值,則使用默認(rèn)值,但是必須顯示指定要賦值的字段,否則會(huì)出錯(cuò)??聪旅娴氖纠?/p>
# 給指定字段賦值,擁有默認(rèn)值的字段使用默認(rèn)值test
postgres=# insert into testdb1(id, parent_id) values(6,30);
INSERT 0 1
postgres=# select * from testdb1;
id | comments | parent_id
----+-------------+-----------
1 | test |
2 | not all |
6 | test | 30
(3 rows)
# 給默認(rèn)值字段賦予一個(gè)新值,此時(shí)使用的是新值。
postgres=# insert into testdb1 values(7, 'my test', 32);
INSERT 0 1
postgres=# select * from testdb1;
id | comments | parent_id
----+-------------+-----------
1 | test |
2 | not all |
3 | test again | 42
5 | not a teste | 35
6 | test | 30
7 | my test | 32
(6 rows)
# 不指定要賦值的字段
postgres=# insert into testdb1 values(8, 35);
INSERT 0 1
postgres=# select * from testdb1;
id | comments | parent_id
----+-------------+-----------
1 | test |
2 | not all |
6 | test | 30
7 | my test | 32
8 | 35 |
(5 rows)
postgres=# insert into testdb1 values(9,,36);
ERROR: syntax error at or near ","
LINE 1: insert into testdb1 values(9,,36);
^
從上面最后兩個(gè)小例子中我們看到,在沒有指定要賦值的字段的時(shí)候,postgresql并不會(huì)自動(dòng)跳過有默認(rèn)值的字段,會(huì)將對(duì)應(yīng)錯(cuò)誤的值賦值給comments字段,也不支持兩個(gè)逗號(hào)表示跳過該字段的功能。因此在給具有默認(rèn)值的字段的表做插入操作時(shí)一定要注意。
刪除表
刪除表應(yīng)該是最簡(jiǎn)單的操作了,命令格式如下:
drop table table_name;
但是要注意的是,如果表的主鍵是另外一張表的外鍵,那么刪除這張表之前一定要先刪除對(duì)應(yīng)表上的外鍵約束,否則會(huì)無法刪除這張表,看下面的示例:
#我們將testdb1的parent_id和testdb2的id設(shè)置為外鍵約束關(guān)系,然后我們來嘗試刪除表testdb2
postgres=# alter table testdb1 add foreign key(parent_id) references testdb2(id);
ALTER TABLE
postgres=# \d testdb1
Table "public.testdb1"
Column | Type | Modifiers
-----------+-----------------------+-----------------------------------
id | integer | not null
comments | character varying(20) | default 'test'::character varying
parent_id | integer |
Indexes:
"testdb1_pkey" PRIMARY KEY, btree (id)
Foreign-key constraints:
"testdb1_parent_id_fkey" FOREIGN KEY (parent_id) REFERENCES testdb2(id)
postgres=# drop table testdb2;
ERROR: cannot drop table testdb2 because other objects depend on it
DETAIL: constraint testdb1_parent_id_fkey on table testdb1 depends on table testdb2
HINT: Use DROP ... CASCADE to drop the dependent objects too.
從提示中我們可以開電腦,無法直接刪除表testdb2,因?yàn)樗闹麈I是testdb1的外鍵,還給出了一個(gè)提示,可以使用DROP .. CASCADE的語法來刪除表testdb2的同事刪除對(duì)應(yīng)依賴的對(duì)象。我們來嘗試一下:
postgres=# DROP table testdb2 CASCADE;
NOTICE: drop cascades to constraint testdb1_parent_id_fkey on table testdb1
DROP TABLE
postgres=# \d testdb1;
Table "public.testdb1"
Column | Type | Modifiers
-----------+-----------------------+-----------------------------------
id | integer | not null
comments | character varying(20) | default 'test'::character varying
parent_id | integer |
Indexes:
"testdb1_pkey" PRIMARY KEY, btree (id)
從上面可以看到,我們使用DROP ... CASCADE的語句來刪除表testdb2的時(shí)候,會(huì)自動(dòng)刪除testdb1表上的外鍵約束,而不需要手動(dòng)去刪除對(duì)應(yīng)的外鍵約束。
上面就是表的創(chuàng)建、修改和刪除的所有內(nèi)容。更高深的操作我們?cè)诤竺媛龑W(xué)習(xí)。下一句繼續(xù)學(xué)習(xí)表相關(guān)的內(nèi)容。