PostgreSQL数据库基础


推荐使用docker安装
安装:
sudo apt update
sudo apt-get install postgresql-16 libpq-dev

官方安装方法:

bash
# 自动配置仓库
sudo apt install -y postgresql-common
sudo /usr/share/postgresql-common/pgdg/apt.postgresql.org.sh
# 安装
sudo apt -y install postgresql

检查是否启动:
sudo systemctl status postgresql

创建用户:
sudo -u postgres createuser --interactive
输入后进行问答,是否为超级用户等

创建新的数据库:
sudo -u postgres createdb <database_name>

给予数据库权限给某用户
sudo -u postgres psql -c "GRANT ALL PRIVILEGES ON DATABASE blog TO username;"

连接数据库:
sudo -u postgres psql
如果是容器需要输入密码
psql -p 5432 -U postgres -d crowdpulse 然后输入密码

为新用户设置密码:
\password <username>

启动和停止

sudo systemctl start postgresql #启动
sudo systemctl stop postgresql #停止
sudo systemctl reload postgresql #重新加载配置生效
sudo systemctl restart postgresql #重启
sudo systemctl status postgresql #查看运行状态

迁移数据库

备份数据库:pg_dump -U 用户名 -d 数据库名 -h 前ip地址 -F c -f 绝对路径.dump
pg_dump -U mymuzixin -d ginbtcmai -h 127.0.0.1 -F c -f /home/ubuntu/ginbtcmai.dump
恢复数据库: pg_restore -U 用户名 -d 数据库名 -h 127.0.0.1 -C -F c 绝对路径.dump

追加表:pg_restore -U 用户名 -d 数据库名 -h 127.0.0.1 -C -c -F c 绝对路径.dump
pg_restore -U username -d ginbtcmai -h 127.0.0.1 --clean --no-owner /home/btcmai2.dump
完全删除库:
sudo -u postgres psql 先进交互
DROP DATABASE djbtcmai; 删除库
CREATE DATABASE 数据库名; 创建空库

python使用

安装py中间件:
sudo apt-get install libpq-dev #依赖库
pip3 install psycopg2 推荐下面的psycopg[binary]这是3版本

如果上面的方法安装错误,也可以选用这个方法:
安装依赖库
sudo apt-get install postgresql-server-dev-10 libpq-dev
#已编译版本(推荐安装这个,第三版)
pip install "psycopg[binary]"
如果不行就安装下面这个
pip install psycopg2-binary

端口和默认时间

/etc/postgresql/版本号/main/postgresql.conf:

ini
listen_addresses = '*'
port = 5432
log_timezone = 'Asia/Shanghai'
timezone = 'Asia/Shanghai'

外网访问

/etc/postgresql/版本号/main/pg_hba.conf
all 是数据库,usdtmai是用户

css
host    all     usdtmai             0.0.0.0/0                 scram-sha-256

postgresql.conf:

ini
listen_addresses = '*'

手动关联删除思路

ini
先遍历循环删除订单明细中订单是31的
然后再删除用户是15的所有订单
最后删除用户
中间如果有其他数据会提示,然后再依次三处该订单关联的明细和订单即可
DELETE FROM ordermxs WHERE orders_id = 31;
DELETE FROM orders WHERE users_id = 15;
DELETE FROM users WHERE id = 15;

修改时区

执行sql查询
show timezone; 显示时区
ALTER DATABASE <数据库名> SET timezone TO 'Asia/Singapore'; 修改时区,修改后要退出会话,下个连接会话生效

容器

bash
docker run -d \
  --name postgres \
  --network backend \
  -e POSTGRES_DB=crowdpulse \
  -e POSTGRES_USER=postgres \
  -e POSTGRES_PASSWORD=123456 \
  -e TZ=Asia/Singapore \
  -p 5432:5432 \
  -v pg-data:/var/lib/postgresql/data \
  --shm-size=1g \
  --restart unless-stopped \
  postgres:17-alpine \
  -c max_connections=500
yaml
services:
	db: # 写了这个db服务,那么容器之间.env写成db代表主机连接到这个库
    image: postgres:17-alpine
    container_name: db
    restart: always
    environment:
      POSTGRES_USER: postgres          # 用户名,可放到 .env
      POSTGRES_PASSWORD: 123456  # 密码,优先取 .env
      POSTGRES_DB: duola               # 初始数据库
	  TZ: Asia/Singapore
    ports:
      - "5432:5432"                   # 宿主机也能访问
    volumes:
      - pgdata:/var/lib/postgresql/data

# 创建一个pgdata的卷,用于存储数据库数据
volumes:
  pgdata:

对齐序列,通常在数据迁移插入了带id字段需要使用

单表序列对齐

sql
SELECT setval(
  pg_get_serial_sequence('public.users', 'id'),
  COALESCE((SELECT MAX(id) FROM public.users), 0),
  true
);

对齐所有表

sql
DO $$
DECLARE
  r RECORD;
  v_max  bigint;   -- 当前表该列的最大 id
  v_curr bigint;   -- 当前序列的 last_value
  v_set  bigint;   -- 要设置给序列的值(一般是二者的较大者)
BEGIN
  -- 遍历所有“默认值是 nextval(...)”的列,也就是 serial/identity 背后有序列的列
  FOR r IN
    SELECT
      c.table_schema,
      c.table_name,
      c.column_name,
      pg_get_serial_sequence(format('%I.%I', c.table_schema, c.table_name), c.column_name) AS seq_name
    FROM information_schema.columns c
    WHERE c.column_default LIKE 'nextval(%'
      AND c.table_schema NOT IN ('pg_catalog','information_schema')  -- 跳过系统 schema
  LOOP
    -- 取该表该列的最大 id(空表则为 0)
    EXECUTE format(
      'SELECT COALESCE(MAX(%I), 0) FROM %I.%I',
      r.column_name, r.table_schema, r.table_name
    ) INTO v_max;

    -- 如果确实有绑定序列(理论上一定有)
    IF r.seq_name IS NOT NULL THEN
      -- 读当前序列的 last_value
      EXECUTE format('SELECT last_value FROM %s', r.seq_name) INTO v_curr;

      -- 计划设置为 max(id) 与 序列当前值 的较大者
      v_set := GREATEST(v_max, v_curr);

      IF v_max = 0 AND v_curr <= 1 THEN
        -- 空表且序列还在初始状态:设置为 1 且 is_called=false(下次 nextval() 返回 1)
        EXECUTE format('SELECT setval(%L, 1, false)', r.seq_name);
        RAISE NOTICE 'Reset empty-table seq % to start at 1', r.seq_name;
      ELSE
        -- 非空表或序列已前进:设置为 v_set 且 is_called=true(下次 nextval() 返回 v_set+1)
        EXECUTE format('SELECT setval(%L, %s, true)', r.seq_name, v_set);
        RAISE NOTICE 'Align seq % to %, next will be %', r.seq_name, v_set, v_set+1;
      END IF;
    ELSE
      RAISE NOTICE 'Skip %.% (column %): no sequence found',
        r.table_schema, r.table_name, r.column_name;
    END IF;
  END LOOP;
END$$;

消耗序列查询下个序列
SELECT nextval('表名_id_seq');

不消耗序列查下个序列,表名填两处

sql
SELECT
  CASE WHEN seq.is_called THEN seq.last_value + p.increment ELSE seq.last_value END AS next_id
FROM public.<name>_id_seq AS seq
CROSS JOIN pg_sequence_parameters('public.<name>_id_seq'::regclass) AS p;

notepad++正则匹配:

(VALUES\s*\()\s*\d+\s*,\s*
替换为
$1
将会把VALUES ('124', 替换为VALUES (

重命名数据库

注意执行sql语句要选择其它库,以及初始连接不能为使用的库,也不能连接这个库
ALTER DATABASE crowdpulse RENAME TO crowdpulse2;