收录一些PostgreSQL日常使用的小命令和小配置,备查。
将sql结果导入csv文件 使用\copy命令将sql结果导入csv文件, postgresql命令行中输入以下命令:1
\copy (Select * From foo) To '/tmp/test.csv' With CSV HEADER
Reference :http://stackoverflow.com/questions/1517635/save-pl-pgsql-output-from-postgresql-to-a-csv-file
将shapefile导入postgresql的步骤 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
$ createdb -U postgres shape_test
$ psql -U postgres shape_test -c "CREATE EXTENSION postgis;";
CREATE EXTENSION
$ shp2pgsql -s 4326 SAMPLE_mt_boundary_201510.shp > shape_file.sql
Shapefile type: Polygon
Postgis type: MULTIPOLYGON[2]
$ psql -U postgres shape_test < shape_file.sql
SET
SET
BEGIN
CREATE TABLE
ALTER TABLE
addgeometrycolumn
---------------------------------------------------------------------------
public.sample_mt_boundary_201510.geom SRID:4326 TYPE:MULTIPOLYGON DIMS:2
(1 row)
INSERT 0 1
INSERT 0 1
COMMIT
$
Reference :
pg_dump多表到一个sql文件中 可以使用多个-t 参数来dump多张表1
$ pg_dump -U postgres db_name -t table1 -t table 2 > output_sql.sql
pg_dump只dump表结构 使用--schema-only
或-s
参数。
如何不dump表结构,只dump数据 可以使用--data-only
来实现1
$ pg_dump --data-only -U postgres db_name -t table1 > output_sql.sql
如果结合--column-inserts
参数使用的话,那么就会为每条记录都生成一个insert语句
使用--column-inserts
的缺点:
sql文件会比较大
从sql恢复(restore)的时候也会很慢.
恢复的时候是单条记录恢复,一条记录错误不会导致整个table的恢复失败, 容易造成数据不完整。
但是适合于导出的sql会用于其他non-PostgreSQL的场景1
$ pg_dump --column-inserts --data-only -U postgres db_name -t table1 > output_sql.sql
Reference : https://www.postgresql.org/docs/9.3/static/app-pgdump.html
在postgresql中建立一个只读用户 建立用户的命令如下:1
CREATE USER intern2019 WITH LOGIN ENCRYPTED PASSWORD 'x!&LosA&@4' VALID UNTIL 'infinity';
对用户授权只读权限的命令如下:
1
2
3
GRANT USAGE ON SCHEMA public TO intern2019;
GRANT SELECT ON ALL TABLES IN SCHEMA public To intern2019; -- only effect by current table
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO intern2019; -- effect by all new table
删除某个用户
1
2
3
4
5
ALTER DEFAULT PRIVILEGES IN SCHEMA public revoke SELECT ON TABLES FROM intern2019
REVOKE ALL PRIVILEGES ON ALL TABLES IN SCHEMA public FROM intern2019;
REVOKE USAGE ON SCHEMA public FROM intern2019
DROP USER intern2019;
如何在group by中统计基于group by字段和其他条件的记录的总数 sum函数中,可以结合case when来统计符合某些条件的总数,在group by的时候,就可以顺带让Postgresql来检查计算符合条件的记录总数,比简单粗暴的子查询来的快速。
1
select mls_id, mls_name, SUM( CASE WHEN (trs_type='long term rentals' or trs_type='' or trs_type is null) THEN 1 ELSE 0 END) as rental_num, SUM( CASE WHEN (trs='for sale') THEN 1 ELSE 0 END) as for_sale_num from listings where active=true and validity=true group by mls_id, mls_name order by mls_id
Reference:
PG的时间函数 原字段加上interval '1 second'
1
2
3
4
5
6
7
postgres=# select NOW(), NOW()+interval '1 second';
now | ?column?
------------------------------+------------------------------
2017-01-09 14:49:38.52691+08 | 2017-01-09 14:49:39.52691+08
(1 row)
postgres=#
查看数据库中各个表上次vacuum和autovacuum时间的sql 1
2
3
4
5
6
7
8
partition_test=# select relname,last_vacuum, last_autovacuum, last_analyze, last_autoanalyze from pg_stat_user_tables;
relname | last_vacuum | last_autovacuum | last_analyze | last_autoanalyze
----------+-------------------------------+-----------------+-------------------------------+------------------
user_new | 2017-05-10 09:30:06.156982+08 | | 2017-05-10 09:30:06.181667+08 |
users | 2017-05-10 09:29:51.52591+08 | | |
(2 rows)
partition_test=#
Postgis中比较geometry类型的值的方法 使用ST_Equals1
select id, source, lat, lon, geom4326, geom, created_at, updated_at from properties where not ST_Equals(geom4326, ST_SetSRID(ST_MakePoint(lon, lat), 4326)) or not ST_Equals(geom, ST_SetSRID(ST_MakePoint(lon, lat), 4269)) limit 1;
PG中查看sql执行时间的方法 使用\timing
来显示sql执行时间,再次输入\timing
关闭显示时间1
2
3
4
5
6
7
8
9
10
11
12
postgres=# \timing
Timing is on.
postgres=# select 1;
?column?
----------
1
(1 row)
Time: 0.214 ms
postgres=# \timing
Timing is off.
postgres=#
切割第一个字符串是不是数字的sql 1
select split_part('10059 Pine Glade Dr', ' ' ,1)~'^([0-9]+\.?[0-9]*|\.[0-9]+)$';
如何建索引时不锁表 Postgresql创建index时,默认是要锁表的。可以通过添加CONCURRENTLY
参数,在不锁表的情况下建立索引。 但需要多次扫描,因此建索引时间会比较久1
create index CONCURRENTLY index_feeds_on_take_id on feeds(take_id);
一些常用的psql命令 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
\l -- 列出所有数据库,数据库字符集等
\l+ -- 列出所有数据库, 也包含数据库size
\c DATABASE_NAME -- 使用某个数据库
\d -- 查看表列表,包含sequence
\dt -- 查看数据库中的表,不包含sequence
\d+ -- 查看表列表(带Size和Description)
\d TABLE_NAME -- 查看表结构
\d+ TABLE_NAME -- 查看表结构,更多信息,比如可显示子表等
\df -- 列出所有的function
\df+ FUNCTION_NAME -- 列出某个function的详细信息
\x -- 打开扩展显示
\q -- 退出
\dt *.* -- 查看当前数据库中所有schema中的表
\dv -- 列出当前数据库中所有的view
\du -- 列出所有的用户
数据库磁盘容量命令 数据库中所有表磁盘空间的命令,包含各个表的大小,索引的大小http://stackoverflow.com/questions/2596624/how-do-you-find-the-disk-size-of-a-postgres-postgresql-table-and-its-indexes 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
SELECT
table_name,
pg_size_pretty(table_size) AS table_size,
pg_size_pretty(indexes_size) AS indexes_size,
pg_size_pretty(total_size) AS total_size
FROM (
SELECT
table_name,
pg_table_size(table_name) AS table_size,
pg_indexes_size(table_name) AS indexes_size,
pg_total_relation_size(table_name) AS total_size
FROM (
SELECT ('"' || table_schema || '"."' || table_name || '"') AS table_name
FROM information_schema.tables
) AS all_tables
ORDER BY total_size DESC
) AS pretty_sizes
PG中重建索引 Postgresql中的索引是不停增长的,当数据被反复删除,更新后,索引文件会变得异常的巨大,称之为”bloated”。 使用reindex
来重建索引,可以减少磁盘空间,提升索引效率。 但直接reindex
重建索引会存在锁表现象。在PostgreSQL 12中才支持reindex
的CONCURRENTLY参数。 12以下的版本中,只能通过手动新建和删除索引的方法来实现。方法如下:
以schema是public,tablename是’feed_records’为例,列出该表下所有索引以及其大小的sql如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
SELECT
t.tablename,
indexname,
c.reltuples AS num_rows,
pg_size_pretty(pg_relation_size(quote_ident(t.tablename)::text)) AS table_size,
pg_size_pretty(pg_relation_size(quote_ident(indexrelname)::text)) AS index_size,
CASE WHEN indisunique THEN 'Y'
ELSE 'N'
END AS UNIQUE,
idx_scan AS number_of_scans,
idx_tup_read AS tuples_read,
idx_tup_fetch AS tuples_fetched
FROM pg_tables t
LEFT OUTER JOIN pg_class c ON t.tablename=c.relname
LEFT OUTER JOIN
( SELECT c.relname AS ctablename, ipg.relname AS indexname, x.indnatts AS number_of_columns, idx_scan, idx_tup_read, idx_tup_fetch, indexrelname, indisunique FROM pg_index x
JOIN pg_class c ON c.oid = x.indrelid
JOIN pg_class ipg ON ipg.oid = x.indexrelid
JOIN pg_stat_all_indexes psai ON x.indexrelid = psai.indexrelid )
AS foo
ON t.tablename = foo.ctablename
WHERE t.schemaname='public' and t.tablename='feed_records'
ORDER BY 1,2;
选一个负载小的时间,重建索引。步骤:
新增一个同原索引内容相同的临时索引A’
删除原来的索引A
重新建原来的索引A
删除新建的临时索引A’1
2
3
4
5
6
7
以重建feed_records中last_update_time字段的索引为例
\d feed_records;
create index CONCURRENTLY xxx_index_feed_records_on_last_update_time on feed_records(last_update_time);
drop index index_feed_records_on_last_update_time;
create index CONCURRENTLY index_feed_records_on_last_update_time on feed_records(last_update_time);
drop index xxx_index_feed_records_on_last_update_time;
\d feed_records;
数据库导出和恢复 数据库导出和恢复命令1
2
3
4
5
6
# 导出数据和表,不包含drop语句
pg_dump --host localhost --username postgres --dbname mydatabase > db.sql
# 导出数据和表,添加-c参数后,会包含drop语句
pg_dump --host localhost --username postgres --dbname mydatabase -c > db.sql
# 恢复表
psql --host localhost --username postgres --dbname mydatabase < db.sql
pg_dump和pg_restore加速 pg_dump在大数据量下dump和restore速度很慢,可以使用-j参数来起多个job并行操作。1
2
$ pg_dump --host localhost -j8 -Fd -v -Uintern -d web_v2_staging -f web_v2_staging_dump
$ pg_restore --verbose --clean --no-acl --no-owner -h localhost -d web_v3_staging -Uintern -j8 --format=d web_v2_staging_dump
输出结果中显示NULL字串 psql的默认输出格式中,没法区分NULL和空字串,使用\pset null (null)
来显示NULL1
2
3
4
5
6
7
8
9
postgres=# \pset null (null);
Null display is "(null);".
postgres=# select NULL;
?column?
----------
(null);
(1 row)
postgres=#
explain analyze用来定位慢查询 针对慢查询,使用explain
和explain analyze
来定位问题。explain
只做评估,并不真正执行sql。explain analyze
会直接运行sql。 一般还需开启\timing
来使用
修改用户密码 修改密码的命令1
ALTER ROLE username WITH PASSWORD 'password';
查看所有的参数
AWS RDS Postgresql master/replicate要修改的几个配置 Master参数修改1
2
wal_keep_segments: 需要需要设大一点,否则写过多的话,会导致replica暂停流复制,从S3下载archived WAL来恢复数据
random_page_cost: 设为seq_page_cost一样的值,默认random_page_cost是4,seq_page_cost是1。SSD磁盘下可以认为顺序查找和随机查找开销是一样的。
Replica参数修改1
2
hot_standby_feedback: 设为1,防止replica查询还在执行时,Master已经将受影响的数据清理掉并同步给replica,导致replica上的查询失败。
random_page_cost: 设为seq_page_cost一样的值,默认random_page_cost是4,seq_page_cost是1。SSD磁盘下可以认为顺序查找和随机查找开销是一样的。
Reference: Best practices for Amazon RDS PostgreSQL replication
查看数据库支持的扩展 查看当前数据库的pg扩展命令SELECT * FROM pg_extension;
或者\dx
查看服务器支持的pg扩展SELECT * FROM pg_available_extensions;
使用SSL/TLS连接数据库 psql中通过添加sslmode
指定模式以及sslrootcert
指定cert路径来使用SSL/TLS1
psql "sslmode=verify-full sslrootcert=./rds-ca-2019-root.pem host=staging-replica.xxxxxxxxxxx.us-east-1.rds.amazonaws.com port=5432 user=db_user dbname=db_name"
sslmode
的说明摘录如下, 来自: https://www.postgresql.org/docs/9.6/libpq-ssl.html
sslmode
Eavesdropping protection
MITM protection
Statement
disable
No
No
I don’t care about security, and I don’t want to pay the overhead of encryption.
allow
Maybe
No
I don’t care about security, but I will pay the overhead of encryption if the server insists on it.
prefer
Maybe
No
I don’t care about encryption, but I wish to pay the overhead of encryption if the server supports it.
require
Yes
No
I want my data to be encrypted, and I accept the overhead. I trust that the network will make sure I always connect to the server I want.
verify-ca
Yes
Depends on CA-policy
I want my data encrypted, and I accept the overhead. I want to be sure that I connect to a server that I trust.
verify-full
Yes
Yes
I want my data encrypted, and I accept the overhead. I want to be sure that I connect to a server I trust, and that it’s the one I specify.
刷新sequence为表的最大值 更新单表 Postgresql的主键自增是通过sequence机制来实现的。重建或者手动insert数据的时候,sequence可能不会被更新。 此时,可以手动更新sequence中的last_value为对应表的最大值。
以users表为例:1
SELECT setval('users_id_seq', (SELECT MAX(id) FROM users));
更新全部表 https://wiki.postgresql.org 上有更新全部表sequence的方法Fixing Sequences
PG的range函数 PG中自带了range类型和函数,可以用来方便的计算数值范围。具体类型,操作符和函数参见官方文档
此处简单摘录一下时间范围tsrange的用法
tsrange类型的定义,使用tsrange(start_time, end_time)来定义一个时间区间,可选的第三个参数,可以来定义区间是开区间还是闭区间。
1
2
3
4
5
6
7
test=# select tsrange('2020-01-01 11:00:00', '2020-01-02 00:00:00'), tsrange('2020-01-01 11:00:00', '2020-01-02 00:00:00', '[]');
tsrange | tsrange
-----------------------------------------------+-----------------------------------------------
["2020-01-01 11:00:00","2020-01-02 00:00:00") | ["2020-01-01 11:00:00","2020-01-02 00:00:00"]
(1 row)
test=#
使用@>
来判定值是否在区间内。
1
2
3
4
5
6
7
test=# select tsrange('2020-01-01 11:00:00', '2020-01-02 00:00:00') @> '2020-01-01 10:00:00'::timestamp as is_in_range;
is_in_range
-------------
f
(1 row)
test=#
使用upper
和lower
来获取区间长度
1
2
3
4
5
6
7
test=# select upper((tsrange('2020-01-01 11:00:00', '2020-01-02 00:00:00'))) - lower((tsrange('2020-01-01 11:00:00', '2020-01-02 00:00:00'))) as length;
length
----------
13:00:00
(1 row)
test=#
使用&&
来判断区间是否重合
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
-- 有区间重合
test=# select tsrange('2020-01-01 00:00:00', '2020-01-02 00:00:00') && tsrange('2020-01-01 23:00:00', '2020-01-02 00:00:00');
?column?
----------
t
(1 row)
-- 没有区间重合
test=# select tsrange('2020-01-01 00:00:00', '2020-01-02 00:00:00') && tsrange('2020-01-02 00:00:00', '2020-01-02 01:00:00');
?column?
----------
f
(1 row)
test=#
创建索引 使用GiST和SP-GiST来为range类型的列来创建索引,可以加速=, &&, <@, @>, <<, >>, -|-, &<, and &>
这几类运算符。
1
2
3
4
5
6
7
8
create table events (
id int primary key,
user_id int not null,
event text not null,
timerange tsrange not null
);
CREATE INDEX timerange_on_events_idx ON events USING GIST (timerange);
使用EXCLUDE来限制重复数据
trim去除首尾空白字符 可以看出,使用了trim
过后,info前后的空白都被去除了。1
2
3
4
5
6
7
test=# select trim(' info ')||',here' as string;
string
-----------
info,here
(1 row)
test=#
清空整个表并回收空间 PostgreSQL中要清空某个表并且回收空间,可以使用TRUNCATE
命令。 官网描述如下:
TRUNCATE quickly removes all rows from a set of tables. It has the same effect as an unqualified DELETE on each table, but since it does not actually scan the tables it is faster. Furthermore, it reclaims disk space immediately, rather than requiring a subsequent VACUUM operation. This is most useful on large tables. 用法:1
TRUNCATE removed_images;
参考: TRUNCATE
创建和查看view 创建view
1
2
3
4
5
6
7
SELECT questions.id AS question_id,
string_agg(question_categories.name::text, ', '::text) AS question_category_name,
array_agg(question_categories.id) AS question_category_ids
FROM questions
JOIN question_question_categories ON question_question_categories.question_id = questions.id
JOIN question_categories ON question_categories.id = question_question_categories.question_category_id AND question_categories.deleted_at IS NULL
GROUP BY questions.id;
查看view, \d+ question_category_view
如何快速删除表中大部分数据 Reference: Best way to delete millions of rows by ID
思路:
创建临时表存放需要保存的数据
truncate
原表
从临时表中把数据重新拷贝回原表中
例子:1
2
3
4
5
6
7
8
9
10
11
12
SET temp_buffers = '1000MB'; -- or whatever you can spare temporarily
CREATE TABLE tmp AS
SELECT t.*
FROM tbl t
LEFT JOIN del_list d USING (id)
WHERE d.id IS NULL; -- copy surviving rows into temporary table
TRUNCATE tbl; -- empty table - truncate is very fast for big tables
INSERT INTO tbl
SELECT * FROM tmp; -- insert back surviving rows.
注意: 源stackoverflow中使用的是CREATE TEMP TABLE
创建的临时表,临时表只对当前session有效。万一truncate
后连接断掉,会导致数据丢失。因此改为CREATE TABLE tmp
比较合理。
拷贝表 拷贝表的语句1
2
CREATE TABLE new_table AS
TABLE existing_table;
如果只需要复制表结构而不包含数据,可以将 WITH NO DATA 子句添加到 CREATE TABLE 语句中。1
2
3
CREATE TABLE new_table AS
TABLE existing_table
WITH NO DATA;
注意拷贝表只有结构和数据,索引是不能复制的,需要在新表中手动添加。
Reference: 如何在 PostgreSQL 中复制表
刷新表的sequence 手动拷贝数据时,由于拷贝的数据会直接insert into
带ID的数据。此时sequence并不会跟随着变化。 拷贝完数据后,就需要刷新sequence id表为表对应的最大值。 方法摘录自: How to reset postgres’ primary key sequence when it falls out of sync?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
-- Login to psql and run the following
-- What is the result?
SELECT MAX(id) FROM your_table;
-- Then run...
-- This should be higher than the last result.
SELECT nextval('your_table_id_seq');
-- If it's not higher... run this set the sequence last to your highest id.
-- (wise to run a quick pg_dump first...)
BEGIN;
-- protect against concurrent inserts while you update the counter
LOCK TABLE your_table IN EXCLUSIVE MODE;
-- Update the sequence
SELECT setval('your_table_id_seq', COALESCE((SELECT MAX(id)+1 FROM your_table), 1), false);
COMMIT;
Amazon Linux 2上安装Postgresql 参考帖子:Install PSQL client on EC2 instance
大概步骤:1
2
amazon-linux-extras install postgresql10
yum install -y postgresql-server postgresql-devel
Postgresql重置postgres密码 如果忘记本地postgres
账号的密码,可以先修改数据库本地登录为trust
模式,此模式下登录账号不需要密码。 方法:
修改pg_hba.conf
中模式为trust
重启pg数据库
1
systemctl restart postgresql-9.3.service
登录数据库修改密码
1
2
3
psql -U postgres
postgres=# alter user postgres with password 'NEW_PASSWORD';
postgresl=# \q
修改pg_hba.conf
中改回为md5
重启pg数据库, 使配置生效。
1
systemctl restart postgresql-9.3.service
参考: Modify The Default Administrator Password
停止一个query查询 查询所有活跃的查询1
SELECT * FROM pg_stat_activity WHERE state = 'active';
终止某个查询1
SELECT pg_cancel_backend(<pid of the process>)
强制杀死某个查询1
SELECT pg_terminate_backend(<pid of the process>)
参考: How to stop/kill a query in postgresql?
按照字段进行distinct on PG中可以使用distinct on (field1, field2)
来针对指定字段来进行去重。 例子如下: 建表1
2
3
4
5
6
create table users(
id SERIAL,
name character varying(255),
sex character varying(255),
age integer
)
插入数据:1
2
3
4
5
6
7
8
9
insert into users(name, sex, age) values('carl', '男', 10);
insert into users(name, sex, age) values('carl', '男', 10);
insert into users(name, sex, age) values('jason', '男', 10);
insert into users(name, sex, age) values('carl', '男', 20);
insert into users(name, sex, age) values('lily', '女', 10);
insert into users(name, sex, age) values('steven', '男', 10);
insert into users(name, sex, age) values('joe', '男', 10);
insert into users(name, sex, age) values('lily', '女', 20);
insert into users(name, sex, age) values('lucy', '女', 10);
例子1: 只针对name进行distinct1
2
3
4
5
6
7
8
9
10
11
12
test=# select distinct on (name) * from users;
id | name | sex | age
----+--------+-----+-----
2 | carl | 男 | 10
3 | jason | 男 | 10
7 | joe | 男 | 10
5 | lily | 女 | 10
9 | lucy | 女 | 10
6 | steven | 男 | 10
(6 rows)
test=#
例子2: 针对name和age来进行distinct1
2
3
4
5
6
7
8
9
10
11
12
13
14
test=# select distinct on (name, age) * from users;
id | name | sex | age
----+--------+-----+-----
2 | carl | 男 | 10
4 | carl | 男 | 20
3 | jason | 男 | 10
7 | joe | 男 | 10
5 | lily | 女 | 10
8 | lily | 女 | 20
9 | lucy | 女 | 10
6 | steven | 男 | 10
(8 rows)
test=#
其中: distinct on ()
,括号里面的内容是要去重的列,括号外面的内容是你要查询展示的列,两者没有关系,你可以根据某些列去重不必将他们查询出来
实现mysql中group by去重的功能 Mysql中,根据某个字段进行去重,可以使用select * from users group by field
的方式来进行,但PG中,对于group by
的时候有严格的规定,select的字段必须要在group by的条件中,或者必须要使用窗口函数。 比如对上面users表使用select * from users group by name
就会报ERROR: column "users.id" must appear in the GROUP BY clause or be used in an aggregate function
的错误。 此时,我们可以使用distinct on (field)
的方法来实现mysql中同样的作用。 在PG中, 使用select distinct on(name) * from users;
就可以实现mysql中select * from users group by name
的作用。如下:1
2
3
4
5
6
7
8
9
10
11
12
test=# select distinct on(name) * from users;
id | name | sex | age
----+--------+-----+-----
2 | carl | 男 | 10
3 | jason | 男 | 10
7 | joe | 男 | 10
5 | lily | 女 | 10
9 | lucy | 女 | 10
6 | steven | 男 | 10
(6 rows)
test=#
参考
CentOS 7下安装Postgresql11 Client CentOS 7 下安装PostgreSQL的命令如下:1
2
3
4
yum install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-7-x86_64/pgdg-redhat-repo-latest.noarch.rpm
yum install -y postgresql11 postgresql11-devel postgresql11-libs postgresql11-contrib
update-alternatives --install /usr/bin/pg_config pgsql-pg_config /usr/pgsql-11/bin/pg_config 1170
如果安装postgresql11-devel
时报告如下错误:1
2
Error: Package: postgresql11-devel-11.16-1PGDG.rhel7.x86_64 (pgdg11)
Requires: llvm-toolset-7-clang >= 4.0.1
那么可以先安装centos-release-scl
仓库, 然后再安装postgresql11-devel
1
yum install centos-release-scl
postgresql中生成随机的时间 以下语句用于生成当前时间之前10000秒内的随机时间1
select NOW() - (floor(random() * 100000 + 1)::int)*'1 second'::interval
函数解释
random()函数随机生成0~1之间的浮点数
floor(random() * 100000 + 1)::int 生成整数形式的随机数
‘1 second’::interval 表示1秒的时间
Reference:
手动生成sequence并关联指定表使用该sequence 情形: news表是从其他库中手动导入的,导入时没有导入对应的sequence,需要手动生成对应的sequence1
2
3
4
5
6
7
8
# 创建sequence
CREATE SEQUENCE news_id_seq START 101;
# 手动关联表news使用上面创建的sequence
ALTER TABLE news ALTER COLUMN id SET DEFAULT nextval('news_id_seq');
# 设置sequence的最大值为表news的最大id
SELECT setval('news_id_seq', (SELECT MAX(id) FROM news));
参考:
PG中如何随机选择数据 使用order by random()
来随机选取数据1
2
3
4
5
SELECT *
FROM words
WHERE Difficult = 'Easy' AND Category_id = 3
ORDER BY random()
LIMIT 1;
参考: Getting a random row from PostgreSQL?
PG中如何替换子字符串 PG中使用replace()
函数将一个指定的字符串中出现的所有指定的子字符串替换为新的子字符串并返回结果。
replace() 语法官网解释: 1
2
3
replace ( string text, from text, to text ) → text
Replaces all occurrences in string of substring from with substring to.
replace('abcdefabcdef', 'cd', 'XX') → abXXefabXXef
replace() 语法 replace(string, search_string, replacement)
参数 string : 必需的。 一个字符串, 也可以是数据库中某个表的字段。search_string : 必需的。 被替换的字符串replacement : 必需的。 替换为的字符串。返回值 PostgreSQL replace() 函数将字符串 string 中的所有的字符串 search_string 使用 replacement 替换,并返回结果。
用法
1
2
3
4
5
#查看修改后结果,并不真实修改数据库
select replace(字段名,'被替换内容','需要替换的内容') from 表名 where 字段名 like E'%被替换内容%';
#更改字段中包含某个字符为另一个字符,这里是把'被替换内容'替换为需要替换的内容。
update 表名 set 字段名=replace(字段名,E'被替换内容','需要替换的内容') where 字段名 like E'%被替换内容%';
例子 将douban_books
表中logo字段中的https://img1.doubanio.com
替换为https://fake.example.com
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
test=# select logo, replace(logo, 'https://img1.doubanio.com', 'https://fake.example.com') from douban_books where id=1;
-[ RECORD 1 ]----------------------------------------------------------
logo | https://img1.doubanio.com/view/subject/s/public/s30064728.jpg
replace | https://fake.example.com/view/subject/s/public/s30064728.jpg
test=#
test=# select logo from douban_books where id=1;
-[ RECORD 1 ]-------------------------------------------------------
logo | https://img1.doubanio.com/view/subject/s/public/s30064728.jpg
test=# update douban_books set logo=replace(logo, 'https://img1.doubanio.com', 'https://fake.example.com') where id=1;
UPDATE 1
test=# select logo from douban_books where id=1;
-[ RECORD 1 ]------------------------------------------------------
logo | https://fake.example.com/view/subject/s/public/s30064728.jpg
test=#
Reference
PG中如何实现类似MySQL中按照FIELD函数排序的功能 mysql order by FIELD函数 MySQL中的FIELD()函数,可以用来对SQL中查询结果集进行指定顺序排序。使用方法:
1
SELECT * from user ORDER BY FIELD(str,str1,str2,str3,...);
排序输出 : 字段str按照str1,str2,str3的顺序返回查询到的结果集。如果表中str的值在str1,str2,str3中不存在,则放在结果集的最前面。
例子:
假如有如下数据:
1
2
3
4
5
6
7
8
9
10
11
12
+
| id | name |
+
| 1 | 绿豆糕 |
| 2 | 红烧排骨 |
| 3 | 赤豆棒冰 |
| 4 | 青椒 |
| 5 | 土豆 |
| 6 | 白馒头 |
| 7 | 菜 |
| 8 | 袜底酥 |
+
如果执行sql按照id 5,3,7的顺序来排序。那么
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
mysql> select id, name from food_items order by field(id, 5,3,7);
+----+--------------+
| id | name |
+----+--------------+
| 1 | 绿豆糕 |
| 2 | 红烧排骨 |
| 4 | 青椒 |
| 6 | 白馒头 |
| 8 | 袜底酥 |
| 5 | 土豆 |
| 3 | 赤豆棒冰 |
| 7 | 菜 |
+----+--------------+
8 rows in set (0.00 sec)
mysql>
此时,id不符合3,5,7的数据先列出,然后3,5,7的数据,按照field函数的顺序进行输出。
如果要让符合field函数中的数先列出,那么可以使用ORDER BY FIELD(str,str1,str2,str3,...) DESC
,不过要注意数据会按照str3
,str2
,str1
的顺序输出。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
mysql> select id, name from food_items order by field(id, 5,3,7) desc;
+----+--------------+
| id | name |
+----+--------------+
| 7 | 菜 |
| 3 | 赤豆棒冰 |
| 5 | 土豆 |
| 1 | 绿豆糕 |
| 2 | 红烧排骨 |
| 4 | 青椒 |
| 6 | 白馒头 |
| 8 | 袜底酥 |
+----+--------------+
8 rows in set (0.00 sec)
mysql>
PG中可以使用ARRAY_POSITION()函数来实现类似的功能 可使用ARRAY
函数先组成一个数组,然后使用ARRAY_POSITION
来获取数值在该数组中的位置的方法来进行排序。使用方法如下:
1
select id, title from news where id in(300473847, 300473832, 300473446, 300473407) order by ARRAY_POSITION(ARRAY[300473847, 300473832, 300473446, 300473407], id)
例子:
假设有如下数据:
1
2
3
4
5
6
7
8
9
10
11
12
# select id, name from listings order by id desc;
id | name
--------+------------------------------------------------------------
193588 | Cedar
193587 | Panama
193586 | Ranch - Andes, NY
193585 | Single Family Residence, Ranch - Benton, LA
193584 | 1 story, Ranch - Janesville, WI
193583 | < 4 Floors, Condo/Coop - Delray Beach, FL
193582 | < 4 Floors, Condo/Coop - Boca Raton, FL
193581 | Log, Single Family,Single Family Detached - Perry Park, KY
(8 rows)
要按照先193582,193585然后其他的顺序显示的话,sql如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# select id, name from listings order by ARRAY_POSITION(ARRAY[193582,193585],id);
id | name
--------+------------------------------------------------------------
193582 | < 4 Floors, Condo/Coop - Boca Raton, FL
193585 | Single Family Residence, Ranch - Benton, LA
193584 | 1 story, Ranch - Janesville, WI
193586 | Ranch - Andes, NY
193587 | Panama
193581 | Log, Single Family,Single Family Detached - Perry Park, KY
193588 | Cedar
193583 | < 4 Floors, Condo/Coop - Delray Beach, FL
(8 rows)
apartment_links=#
要逆序的话,加上DESC
即可。
1
2
3
4
5
6
7
8
9
10
11
12
# select id, name from listings order by ARRAY_POSITION(ARRAY[193582,193585],id) desc;
id | name
--------+------------------------------------------------------------
193581 | Log, Single Family,Single Family Detached - Perry Park, KY
193587 | Panama
193588 | Cedar
193583 | < 4 Floors, Condo/Coop - Delray Beach, FL
193584 | 1 story, Ranch - Janesville, WI
193586 | Ranch - Andes, NY
193585 | Single Family Residence, Ranch - Benton, LA
193582 | < 4 Floors, Condo/Coop - Boca Raton, FL
(8 rows)
参考
PostgreSQL中指定null在order by中的排序 null在order by中的默认排序 在默认情况下,PG中NULL
在ASC
中是排在最末尾的,在DESC
中是排在最前面的。 测试如下:1
2
3
4
5
6
7
8
9
10
-- 建表
CREATE TABLE cities (e_name VARCHAR(70), c_name VARCHAR(70));
-- 插入数据
INSERT INTO cities VALUES ('Suzhou', '苏州');
INSERT INTO cities VALUES (NULL, '占位1');
INSERT INTO cities VALUES ('Beijing', '北京');
INSERT INTO cities VALUES ('Shenzhen', '深圳');
INSERT INTO cities VALUES (NULL, '占位2');
INSERT INTO cities VALUES ('Shanghai', '上海');
执行order by asc
和order by desc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
test=# select * from cities order by e_name asc;
e_name | c_name
----------+--------
Beijing | 北京
Shanghai | 上海
Shenzhen | 深圳
Suzhou | 苏州
| 占位1
| 占位2
(6 rows)
test=# select * from cities order by e_name desc;
e_name | c_name
----------+--------
| 占位1
| 占位2
Suzhou | 苏州
Shenzhen | 深圳
Shanghai | 上海
Beijing | 北京
(6 rows)
test=#
可以明确的看到,默认情况下,asc
下null值排在最末尾,desc
下null值排在最前面。
修改null在order by中的排序 在实际使用中,默认排序可能和业务逻辑是不相符的,此时可以在order
中使用关键字nulls first
和nulls last
来调整排序规则。 如果我们在order by asc
中想要将null排在前面,就可以加上nulls first
。1
2
3
4
5
6
7
8
9
10
11
12
test=# select * from cities order by e_name asc nulls first;
e_name | c_name
----------+--------
| 占位1
| 占位2
Beijing | 北京
Shanghai | 上海
Shenzhen | 深圳
Suzhou | 苏州
(6 rows)
test=#
如果我们想要在order by desc
中将null排在最后面,就可以加上nulls last
。1
2
3
4
5
6
7
8
9
10
11
12
test=# select * from cities order by e_name desc nulls last;
e_name | c_name
----------+--------
Suzhou | 苏州
Shenzhen | 深圳
Shanghai | 上海
Beijing | 北京
| 占位1
| 占位2
(6 rows)
test=#
索引使用 PG默认的order规则就是order by asc nulls last
, order by desc nulls first
, 此时普通的btree索引可以被查询使用。 但如果使用order by asc nulls first
或者order by desc nulls last
后,普通的字段btree索引就无法使用。可以使用如下的方式来建立对应的索引1
2
CREATE INDEX foo_idx ON tbl (last_updated DESC NULLS LAST);
CREATE INDEX foo_idx ON tbl (last_updated ASC NULLS FIRST);
此时使用order by last_updated DESC NULLS LAST
或order by last_updated ASC NULLS FIRST
就可以使用对应的索引了。
Reference