1、表
由行和列组成,列的数量和顺序是固定的,每一个列都有一个名字,行是可变的-反映在给定某个时刻它所存储的数据。SQL不会保证表中行的顺序,当一个表被读时,这些行会出现在一个未指定的顺序中,除非明确要求排序。此外SQL不会为这些行指定唯一标识符。
每个列都有相应的数据类型,限制可能值的集合和可用于计算的数据。eg:数值类型不能接受任意的文本字符串,存储的数据适合数学计算。字符串类型可以接受大多种类型的数据,但它不适合数学计算,虽然其他操作可用(字符串的连接)
CREATE TABLE my_first_table (
first_column text,
second_column integer
);
表包含列的数量限制取决于列的类型,一般是在256~1600
DROP TABLE my_first_table;
删除一个不存在的表时得到一个错误,而sql脚步中是常见的,在创建表之前尝试无条件的删除表,忽略任何错误信息,脚本的作用是该表是否存在,如为避免错误消息,但不是sql标准,可以使用:
DROP TABLE IF EXISTS
2、默认值
一个列可指定一个默认值,当一个新行被创建并且一些没有指定值,那这些列将被它们各自的默认值填充。如没有明确的声明默认值,该默认值为null值(未知的数据)。
CREATE TABLE products (
product_no integer,
name text,
price numeric DEFAULT 9.99
);
默认值也可使用表达式,当默认值被插入时,将对该表达式求值。如:timestamp列通常有一个CURRENT_TIMESTAMP默认值(方便获取or设置当前的时间);为每一行生成序列号,在pg中通常如下设置:
CREATE TABLE products (
product_no integer DEFAULT nextval('products_product_no_seq'),
...
);
从一个连续序列中获取值,它有一个特殊的写法:
CREATE TABLE products (
product_no SERIAL,
...
);
3、约束
数据类型是限制数据可以存储表中的一种方式,SQL容许在列和表上定义约束,约束提供对表里数据的控制。如果用户违反约束存储数据,将引发一个错误
a、check约束
指定在某一列中的值必须满足一个布尔表达式(真值)
CREATE TABLE products (
product_no integer,
name text,
price numeric CHECK (price > 0)
);
可以为约束指定一个分离的名字,错误信息更清楚并容许你引用该约束当你需要修改它,语法:
CREATE TABLE products (
product_no integer,
name text,
price numeric CONSTRAINT positive_price (price > 0)
);
check约束可以引用多个列,该约束定义在表上
CREATE TABLE products (
product_no integer,
name text,
price numeric CHECK (price > 0)
discounted_price numeric CHECK (discounted_price > 0),
CHECK (price > discounted_price)
);
注意:check约束确信检查表达式位true或者null值,不会阻止约束的列为null
b、not-null约束
指定一列不能有null值,语法:
CREATE TABLE products (
product_no integer NOT NULL,
name text NOT NULL,
price numeric
);
not-null约束总是作为列的约束,等同于check (column_name is not null)约束,但pg创建not-null约束更有效,缺点是你不能为其指定名称。
c、unique约束
确保包含在一列or一组列的数据是唯一的相对于表中的所有行,语法:
CREATE TABLE products (
product_no integer UNIQUE,
name text,
price numeric
);
写成表约束:
CREATE TABLE products (
product_no integer,
name text,
price numeric,
UNIQUE(product_no)
);
添加unique约束将自动创建在列or一组列创建一个unique btree index.2个null值在该约束中不认为是相同的,这意味着在一个unique约束下可以存储重复的行数据(包含null值的列中),这种行为符号sql标准,但可能其他数据库不实现这个规则。
d、primary keys
简单的由unique约束和not-null约束构成,语法:
CREATE TABLE products (
product_no integer PRIMARY KEY,
name text,
price numeric
);
功能类似于
CREATE TABLE products (
product_no integer UNIQUE NOT NULL,
name text,
price numeric
);
定义多个列,语法:
CREATE TABLE example (
a integer,
b integer,
c integer,
PRIMARY KEY (a, c)
);
注意:一张表可以有至多一个primary key,可以有多个unique和not-null约束,功能和primary key相同,但只有一个可以确定为primary key,关系数据库理论强调每个表必须有一个primary key,该规则pg不强制,但通常是遵守它。
e、foreign keys
列or一组列中的值必须在另一个表中一些行中找到匹配的值,保持2个相关表之间引用的完整性
语法:
CREATE TABLE products (
product_no integer PRIMARY KEY,
name text,
price numeric
);
CREATE TABLE orders(
order_id integer PRIMARY KEY,
product_no integer REFERENCES products (product_no),
quantity integer
);
可以定义一组列foreign key在表上(列的数量和类型需要对应匹配):
CREATE TABLE t1 (
a integer PRIMARY KEY,
b integer,
c integer,
FOREIGN KEY (b, c) REFERENCES other_table (c1, c2)
);
注意:一个表可以有多个foreign key,可用作表之间many-to-many的关系
CREATE TABLE products (
product_no integer PRIMARY KEY,
name text,
price numeric
);
CREATE TABLE orders (
order_id integer PRIMARY KEY,
shipping_address text,
...
);
CREATE TABLE order_items (
product_no integer REFERENCES products ON DELETE RESTRICT,
order_id integer REFERENCES orders ON DELETE CASCADE,
quantity integer,
PRIMARY KEY (product_no, order_id)
);
RESTRICT delete:防止删除一个引用行,意味着任何引用的行还存在约束检查,将抛出错误,如果你不指定将为默认行为。
CASCADE delete:当一个引用行被删除时,引用它的行也自动删除。
类似删除还有更新操作。通常,一个引用的行如果它引用的列是null是不需要满足foreign key约束,如果MATCH FULL添加到外键声明时,引用行不满足约束只有在其引用的列是null值。若你想引用行满足foreign key,那声明应用列为not null。
Foreign key必须引用primary key 或 unique 约束列,意味着引用列总是有一个index,所以检查是否有引用行匹配是有效的,因为从引用表删除行or更新引用的列将需要扫描应用表匹配的旧值行,这往往是使用index引用列的好方式。
4、系统列
每一张表都隐式的定义了几个系统列,因此,这些名称不能做用户定义的名称,不用过多关注这些列,只需指定它们存在
oid:一行的对象标示符,如果表是使用OIDS创建的,该列是唯一存在的
tableoid:包含该行的表的OID,该列为查询继承层次方便
xmin:行版本插入事务标示符
cmin:在插入事务内命令标示符,从0开始
xmax:删除事务的标示符,或0为一个未删除行版本,在一个可见的行版本中,这列可能是非0,表明该删除操作还没有提交,或试图回滚
cmax: 在删除事务内命令标示符,或0
ctid:表中行版本的物理位置,尽管ctid可以很快定位行版本,但如果它被更新or移动,那么该ctid会修改。因此ctid是很少用的,OID,甚至更好的用户定义序列可以用来识别逻辑行
5、修改表
添加列
ALTER TABLE products ADD COLUMN description text;
移除列
ALTER TABLE products DROP COLUMN description;
如果列通过foreign key被另一个表引用,pg不会删除约束,你可以通过添加CASCADE授权删除所有该列上的依赖:
ALTER TABLE products DROP COLUMN description CASCADE;
添加一个约束
表约束语法:
ALTER TABLE products ADD CHECK (name <> '');
ALTER TABLE products ADD CONSTRAINT some_name UNIQUE (product_no);
ALTER TABLE products ADD FOREIGN KEY (product_group_id) REFERENCES product_groups;
添加not-null约束
ALTER TABLE products ALTER COLUMN product_no SET NOT NULL;
移除一个约束
ALTER TABLE products DROP CONSTRAINT some_name;
可以同删除列一样添加CASCADE,删除not-null约束:
ALTER TABLE products ALTER COLUMN product_no DROP NOT NULL;
修改列上的默认值
ALTER TABLE products ALTER COLUMN price SET DEFAULT 7.77;
这不会影响到表中任何现有行,只是改变将来插入的数据
移除列的默认值
ALTER TABLE products ALTER COLUMN price DROP DEFAULT;
等同默认设置为null值
修改列的数据类型
ALTER TABLE products ALTER COLUMN price TYPE numeric(10,2);
这只有在现有条目中的列可以隐式转换成新的列类型时才会成功,若复杂转换,可使用USING指定如何从旧值转换到新值
列重命名
ALTER TABLE products RENAME COLUMN product_no TO product_number;
表重命名
ALTER TABLE products RENAME TO items;
6、privileges
当一个对象被创建后,可以指定其owner,该owner通常是执行创建语句的角色。大多数对象,初始状态是只有owner或超级用户可以使用该对象,要使其他角色使用,privileges必须被授予
GRANT UPDATE ON accounts TO joe;
joe是已存在的用户,accounts是已存在的表,授予update权限
撤销权限:REVOKE ALL ON accounts FROM PUBLIC;
7、schemas
pg集群包含一个or多个数据库,用户和用户组是通过集群共享。但没有其他数据是通过数据库共享的,任何给定的客户端连接到服务器只能访问连接请求指定的单一数据库的数据。
一个数据库包含一个or多个schemas,schemas中包含表及其他多种对象。相同的对象名称在不同的schemas是不冲突的。不同于数据库,schemas并不严格分开的,连接用户(有权限)是可以访问数据库中的任何schemas,有如下原因可能需要使用schemas:
1、允许多个用户互不干扰的使用同一个数据库
2、对数据库对象进行逻辑分组,使之易于管理
3、第三方应用程序可放在不同的schemas,使它们的名字不会与其他对象冲突
schemas类似与os的目录,但schemas是不能嵌套
创建schemas:
create schema myschema;
通常,创建一个归属某用户特定的schema,语法如下:
create schema myschema authorization username;
在schema中创建or访问对象,使用如下:
schema.table
实际上,更一般的语法为:database.schema.table; database必须是你连接到的数据库
在一个新的schema中创建表,语法:
create table myschema.mytable(
… ...
);
删除schema语法:
drop schema myschema;--myschema为空
drop schema myschema cascade; --myschema包含数据对象时
public schema
前面我们创建表没有使用任何指定的schema名字,默认的表和其他数据对象都自动添加到一个public schema中,每一个新的数据库都包含一个public schema,所以下面是等价的:
create table products (… ...);
create table public.products (… ...);
schema搜索路径
系统在一个schema列表中确定表的搜索路径,第一个匹配的表被查找,若在搜索路径中不匹配,报告错误,即使匹配表的名字存在其他数据库的schema中。
在搜索路径中的第一个schema叫做当前的schema,显示当前的搜索路径,语法:
show search_path;
在搜索路径中添加一个新的schema,就可以不使用schema来直接访问对象,语法:
set search_path to myschema,public;
schemas and privileges
默认在schema中,用户不能访问不属于他的任何对象,因此,schema的所有者必须给该schema授权USAGE privilege ,让用户能够使用schema中的对象。
用户也可以在别的schema中创建对象,该schema必须授权create privilege,注意,默认情况下,每个用户在public schema都有 create 和 usage privilege。你可以撤销这个授权:
revoke create on schema public from public;
第一个public:指schema; 第二个public:指每个用户
system catalog schema
除了public 和 用户创建的schema,每个数据库都含有一个pg_catalog schema,该schema中包含了系统表、内置的数据类型、功能和操作。pg_catalog schema总是有效搜索路径的一部分。
8、partitioning
分离逻辑上一大表到较小的物理块,partitioning提供很多好处:
a、当大部分的大量访问表中的行在一个分区时,查询的性能大大提高,使用分区取代主要列的索引,减少索引的大小和有可能会使大量使用的索引部分装入内存
b、当查询or更新访问单一分区的大百分比,通过有效顺序扫描提高性能,分区取代通过整表随机访问读取扫描和使用索引
c、大容量的加载和删除可以通过添加和删除分区完成,如果规划分区设计,alter table no inherit 和 drop table更快与大容量操作,这些命令也完全避免通过批量Delete引起vacuum overhead开销
d、很少使用的数据也可被转移到更便宜or缓慢的存储媒体
当表非常大时,这样做的好处是值得的。确切好处取决了应用,虽然简单的规则是,表的大小超过数据库服务器的物理内存。
目前,pg通过表的继承来支持partitioning。每一个分区被当做父表的一个子表创建。通常父表是空的,只是代表整个数据集。Pg中实现如下的partitioning:
Range Partitioning
表被划分到“ranges”,通过关键列or列集定义,分配到不同分区之间range的值是不重叠,如一个可能的日期范围分区or特定业务对象标识符的范围
List Partitioniong
通过明确的列出关键值出现在每个分区
实现分区
a、创建“master”表,所有的分区都继承它
b、创建几个继承“master”的“child”表,所有列继承“master”表,将“child”表作为分区
c、在每个分区定义允许的关键值添加约束,如:
check( x=1 )
check( outletID >= 100 and outletID <200 )
确保每个分区之间允许值没有重叠,在range 和 list分区的语法没有区别
d、为每一个分区在关键列上创建索引
e、可选操作,定义一个trigger 或 rule将插入主表数据重定向到适当的分区
f、确保postgresql.conf的constraint_exclusion没有禁用,如果禁用,查询不会优化