本文可帮助具有MySQL基础的小伙伴对PostgreSQL做一个快速的入门,通过语法之间的差异对比,降低学习成本,同样都是数据库,正所谓触类旁通。
模式(Schema)表示数据库中的逻辑容器,用于组织和管理数据库对象,如表、视图、索引等。一个模式可以看作是一组相关对象的命名空间。
模式不同于表,它更多地是对数据库对象进行逻辑分组和隔离的一种方式。一个模式可以包含多个表,每个表又可以属于不同的模式。通过使用模式,可以将相关的数据库对象组织在一起,提供更好的可管理性和安全性。
模式的主要作用有:
users
"的表,在模式B下也可以创建一个名为"users
"的表,它们互不冲突。TEXT
数据类型没有此限制。TINYINT
、MEDIUMINT
和INT
表示不同大小的整数,而PostgreSQL使用SMALLINT
、INT
和BIGINT
。''
或""
来表示字符串,而PostgreSQL只接受''
来表示字符串。E'…'
来表示带有转义序列的字符串。VARCHAR
来表示可变长度的字符串,例如 VARCHAR(255)
,VARCHAR(n)
最大只能是64kb。而postgresql中的VARCHAR(n)
最大可以存 1GB。
VARCHAR
或 TEXT
来表示可变长度的字符串,postgresql中的TEXT
相当于MySQL中的longtext
。integer[]
、varchar[]
等。"+"
或CONCAT
函数来连接字符串,而在PostgreSQL中,可以使用"||"
来连接字符串。-- 使用双竖线进行字符串连接
SELECT 'Hello' || ' ' || 'World'; -- 输出结果为 'Hello World'
-- 使用 CONCAT 函数进行字符串连接
SELECT CONCAT('Hello', ' ', 'World'); -- 输出结果为 'Hello World'
-- 直接使用空格符号进行字符串连接
SELECT 'Hello' ' ' 'World'; -- 输出结果为 'Hello World'
NOW()
来获取当前日期时间,而PostgreSQL使用CURRENT_TIMESTAMP
或CURRENT_DATE
来获取。DATE_ADD()
、DATE_SUB()
等函数来添加或减少日期时间,而PostgreSQL使用INTERVAL
进行类似操作。-- 在当前日期上添加3天
SELECT DATE_ADD(CURDATE(), INTERVAL 3 DAY);
-- 在当前日期上减去1周
SELECT DATE_SUB(CURDATE(), INTERVAL 1 WEEK);
-- 在当前日期上添加3天
SELECT CURRENT_DATE + INTERVAL '3 day';
-- 在当前日期上减去1周
SELECT CURRENT_DATE - INTERVAL '1 week';
"LIMIT offset, count"
,offset
为起始位置,count
为返回记录数。"LIMIT count OFFSET offset"
,count
为返回记录数,offset
为起始位置。count
表示要返回的记录数,offset 表示返回记录集开始的位置。如果省略 offset 参数,则默认从第一条记录开始。举例:
SELECT name, score
FROM student
ORDER BY score DESC
LIMIT 5;
SELECT name, score
FROM student
ORDER BY score DESC
LIMIT 5 OFFSET 3;
-- 跳过前3个记录,然后获取接下来的5个记录
请注意,LIMIT 子句需要与 ORDER BY 子句一起使用来保证结果集的正确性。否则,返回的结果可能会是没有排序的任意行。
= NULL
"或"IS NULL
"来检查NULL值,使用"IS NOT NULL
"来检查非NULL值。IS NULL
"来检查NULL值,使用"IS NOT NULL
"来检查非NULL值。AUTO_INCREMENT
关键字将主键列设置为自增列。SERIAL
或BIGSERIAL
类型来创建自增主键列。举例:
-- 使用 SERIAL 类型创建自增主键列
CREATE TABLE users (
id SERIAL PRIMARY KEY,
username VARCHAR(50),
email VARCHAR(100)
);
-- 使用 BIGSERIAL 类型创建自增主键列
CREATE TABLE products (
id BIGSERIAL PRIMARY KEY,
name VARCHAR(100),
price DECIMAL(10,2)
);
注意:
使用 SERIAL
类型时,自增的主键列将存储 **4 字节大小的整数值,范围从 1 到 2,147,483,647。
而使用 BIGSERIAL
类型时,自增的主键列将存储 8 **字节大小的整数值,范围从 1 到 9,223,372,036,854,775,807。
无论使用 SERIAL
还是 BIGSERIAL
类型,都要将其指定为主键(PRIMARY KEY)
以确保唯一性和索引优化。通过使用这些自增类型,可以方便地为表创建带有自动生成的唯一标识符的主键列。
@
符号来声明和使用用户变量,使用?
来作为占位符来传递参数。:
)来声明和使用变量,使用$1
、$2
等占位符来传递参数。-- 声明一个名为my_var的用户变量,并将其赋值为'Hello World'
SET @my_var := 'Hello World';
-- 打印变量的值
SELECT @my_var;
----------------------------------------------
-- 查询指定用户的信息,使用占位符传递参数
SELECT username, email
FROM users
WHERE id = ?;
-- 声明一个名为my_var的变量,并将其赋值为'Hello World'
DO $$
DECLARE
my_var TEXT := 'Hello World';
BEGIN
-- 打印变量的值
RAISE NOTICE 'The value of my_var is: %', my_var;
END $$;
-----------------------------------------
-- 查询指定用户的信息,使用占位符传递参数
SELECT username, email
FROM users
WHERE id = $1;
JOIN
、LEFT JOIN
、RIGHT JOIN
和INNER JOIN
来进行不同类型的连接。JOIN
来进行内连接,使用LEFT JOIN
和RIGHT JOIN
来进行左连接和右连接。HAVING SUM(column) > 100
。而在 MySQL 中,默认情况下不允许在 HAVING 子句中直接使用 SELECT 语句中定义的聚合函数结果,需要使用重复的聚合函数表达式,如 HAVING SUM(column) > 100
和 HAVING SUM(column) > 200
。HAVING column IS NULL
。而在 MySQL 中,需要使用特殊函数 IS NULL 或 IS NOT NULL 进行 NULL 值的比较,如 HAVING IS NULL(column)
。GROUP BY
子句中,要么在聚合函数中使用。否则,会引发错误。在MySQL中:
SELECT name, AVG(score) AS avg_score
FROM student
GROUP BY name;
在postgreSQL中
SELECT name, AVG(score) AS avg_score
FROM student
GROUP BY name;
--- 报错!!!
可以看到,MySQL 允许在 SELECT 子句中使用聚合函数,而 PostgreSQL 要求使用 GROUP BY
子句,并确保所有非聚合列都在GROUP BY
子句中。
UTF-8
、Latin1
、WIN1251
等。可以通过创建数据库时指定编码或者修改已有数据库的编码来设置。UTF-8
、GBK
、GB2312
等。可以通过创建数据库时指定字符集或者修改已有数据库的字符集来设置。LC_COLLATE
环境变量或 SET
命令来更改。例如,如果使用以英文为基础的区域设置,则会在排序中将大写字母与小写字母一起处理。此外,PostgreSQL还支持自定义排序规则。utf8
字符集下,MySQL 按照Unicode标准进行排序,因此对于不同语言的字符排序可能会有所不同。MySQL
支持使用 COLLATE
关键字来指定排序规则。包括点(point)、直线(line)、线段(lseg)、路径(path)、多边形(polygon)、圆(cycle)等类型。
PostgreSQL中特有的类型,其他数据库中一般没有此类型,可以认为是一种数据库内置的自定义类型。
CREATE TABLE places (
id SERIAL PRIMARY KEY,
name VARCHAR(100),
location GEOMETRY(Point, 4326)
);
INSERT INTO places (name, location) VALUES ('Central Park', ST_GeomFromText('POINT(-73.968500 40.785800)', 4326));
有cidr
、inet
、macaddr
3种类型
PostgreSQL中特有的类型,其他数据库中一般没有此类型,可以认为是一种数据库内置的自定义类型。
CREATE TABLE users (
id SERIAL PRIMARY KEY,
name VARCHAR(100),
ip_address INET
);
INSERT INTO users (name, ip_address) VALUES ('Alice', '192.168.0.1');
postgresql中可以直接存储一个数组,对应其他数据库中没有此类型。
可以在表中存储和操作多个数值或对象
CREATE TABLE products (
id SERIAL PRIMARY KEY,
name VARCHAR(100),
prices INTEGER[]
);
INSERT INTO products (name, prices) VALUES ('Apple', ARRAY[10, 15, 20]);
range类型,可以存储范围数据,其他数据库中无此类型
用于表示一定范围内的数值或时间戳等数据。
CREATE TABLE events (
id SERIAL PRIMARY KEY,
name VARCHAR(100),
event_time TSRANGE
);
INSERT INTO events (name, event_time) VALUES ('Meeting', '[2023-09-10 09:00, 2023-09-10 10:00]');
PostgreSQL 具有特殊的对象标识符类型,用于存储和引用数据库对象的标识,如表、列、模式等。
CREATE TABLE orders (
id SERIAL PRIMARY KEY,
order_number OID,
product_name VARCHAR(100)
);
INSERT INTO orders (order_number, product_name) VALUES ('163125', 'Computer');
着重介绍一下该类型,因为经常会碰到postgresql中存储JSON数据。
JSON数据类型可以用来存储JSON(JavaScript Object Notation)
数据,而JSON数据格式是在RFC 4627
中定义的。当然也可以使用 text
、varchar
等类型来存储JSON数据,但使用这些通用的字符串格式 将无法自动检测字符串是否为合法的JSON数据。而且,JSON数据类型还可以使用丰富的函数。
JSON数据类型是从PostgreSQL 9.3版本开始提供的,在9.3版本中 只有一种类型JSON,在PostgreSQL 9.4版本中又提供了一种更高效的类型JSONB
,这两种类型在使用上几乎完全一致,两者主要区别是:
JSON类型是把输入的数据原封不动地存放到数据库中(当然在存储前会做JSON的语法检查),使用时需要重新解析数据;
而JSONB类型是 在存储时就把JSON解析成二进制格式,使用时就无须再次解析,所以 JSONB在使用时性能会更高。
另外,JSONB支持在其上建索引,而 JSON则不支持,这是JSONB类型一个很大的优点。 因为JSON类型是把输入的整个字符串原封不改动地保存到数据库 中,因此JSON串中key之间多余的空格也会被保留下来。而且,如果JSON串中有重复的key,这些重复的key也会保留下来(默认处理时以最后一个为准),同时也会保留输入时JSON串中各个key的顺序。而 JSONB类型则恰恰相反,既不会保留多余的空格,也不会保留key的顺序和重复的key。
PostgreSQL中每个数据库只允许用一种服务器编码,如果数据库的编码不是UTF-8,PostgreSQL中的JSON类型是无法严格遵循JSON规范中对字符集的要求的。如果输入中包含无法在服务器编码中表示的字符数据,将无法导入数据库中。但是,能在服务器编码中表示的非 UTF-8字符则是被允许的。
可以使用**\uXXXX**
形式的转义,从而忽视数据库的字符集编码。 当把一个JSON类型的字符串转换成JSONB类型时,JSON字符串内的数据类型实际上被转换成了PostgreSQL数据库中的类型,两者的映射关系见下表。
需要注意的是,如果是在JSONB中,不能输入超出 PostgreSQL的numeric数据类型范围的值。
JSON的类型 | PostgreSQL 类型 | 注意事项 |
---|---|---|
string | text | 注意字符集的一些限制 |
number | numeric | JSON中没有PostgreSQL中的“NaN”和“infinity”值 |
boolean | boolean | JSON仅能接受小写的“true”,和“false” |
null | (none) | SQL中的NULL代表不同的意思 |
-- 创建表
CREATE TABLE students (id SERIAL PRIMARY KEY, info JSONB);
-- 向表中插入 JSON 数据
INSERT INTO students (info)
VALUES ('{"name": "Alice", "age": 20, "major": "Computer Science"}'),
('{"name": "Bob", "age": 22, "major": "Mathematics"}');
SELECT info FROM students;
SELECT info->>'name' AS name, info->>'age' AS age
FROM students
WHERE info->>'major' = 'Computer Science';
这里解释一下箭头符号的使用:
properties->'rotation'
表示从 JSONB 字段 “properties
” 中提取键为 “rotation
” 的子字段的值。properties->>'deviceIp'
表示从 JSONB 字段 “properties
” 中提取键为 “deviceIp
” 的子字段的值,并将其作为字符串返回。CREATE TABLE products (
id INT,
details JSONB
);
INSERT INTO products (id, details) VALUES
(1, '{ "name": "iPhone", "price": 999, "specs": {"color": "silver", "storage": "64GB"}}'),
(2, '{ "name": "iPad", "price": 699, "specs": {"color": "gray", "storage": "128GB"}}'),
(3, '{ "name": "MacBook Pro", "price": 1999, "specs": {"color": "space gray", "storage": "256GB"}}');
-- 建好表后看一下数据
现在,我们想从 “details” 字段中提取商品的名称、价格和颜色作为查询结果的列。
SELECT
details -> 'name' AS NAME,
details -> 'price' AS price,
details -> 'specs' ->> 'color'
FROM
products
区别如下:
看我下面这个例子,上面的可能看起来难以理解,但是都是理论,接着看下实操:
看我标注出来的地方,可以看到,如果是一个对象,直接用->>
是取不出来的,直接为null了,虽然不会报错。
所以必须先拿到父级,再从中取出子字段。
以上代码分别从 JSONB 类型的字段中提取了特定的键值对,并将其作为查询结果的列。这种用法适用于 PostgreSQL 数据库中存储了 JSONB 类型数据的情况。
SELECT info->>'name' AS name, info->>'age' AS age
FROM students
WHERE info @> '{"major": "Computer Science"}'
ORDER BY (info->>'age')::INTEGER;
@>
运算符用于检查 JSON 对象包含某个特定键或值。
这里顺便补充一下这个@>
的语法
@>
操作符是 PostgreSQL 中针对 JSON 数据类型的操作符之一,它表示“包含”。具体而言,它用来检查一个 JSON 对象是否包含另一个 JSON 对象中的所有键值对。
使用 @>
操作符时,需要提供两个参数。第一个参数是查询对象,通常是一个 JSONB 列名或者一个 JSON 字面量。**第二个参数是要匹配的对象,也通常是一个 JSON 字面量。**如果查询对象中包含第二个参数中所有的键值对,则返回 true,否则返回 false。
示例:
SELECT * FROM my_table WHERE my_column @> '{"name": "Alice"}'
这一句sql会检查 my_column
列中的 JSONB 数据是否包含 { "name": "Alice" }
这个 JSON 对象中的所有键值对。如果匹配成功,则返回匹配行的所有内容。
在 JSON 值之间深度比较时,@>
操作符也可以与其他 JSON 操作符(如 ->, ->>, #>, #>>
等)结合使用,以实现更复杂的 JSON 查询。
data #> '{key1, key2, key3}'
,其中 data 是一个 JSONB 列,'{key1, key2, key3}'
是表示键路径的文本数组。data #>> '{key1, key2, key3}'
,其中 data 是一个 JSONB 列,'{key1, key2, key3}'
是表示键路径的文本数组。SELECT data #> '{key1, key2}' AS sub_object
FROM my_table;
-- 这将返回 JSONB 列 data 中,键路径为 key1 -> key2 的子对象。
SELECT data #>> '{key1, key2}' AS text_value
FROM my_table;
-- 这将返回 JSONB 列 data 中,键路径为 key1 -> key2 的文本值。
->
和 ->>
只能获取单个键的值或文本值,而 #>
和 #>>
可以获取嵌套键的值或文本值。->
和 #>
使用相似的方式,都需要指定一个键或键路径来访问 JSONB 对象中的值。->>
和 #>>
类似于 ->
和 #>
,但返回的是文本值而不是原始 JSONB 值。为了提高SQL的兼容性,部分数据类型还有很多别名,如integer
类型,可以用int
、int4
表示,smallint
也可以用int2
表示;char
varying(n)
可以用varchar(n)
表示,numeric(m,n)
也可以用decimal(m,n)
表示,等等。