第十一章 PostgreSQL 服务器编程知识点梳理(1)

一、前置回顾:数据库安全性与完整性

(一)存取控制

  • 核心目标:仅允许用户访问或修改其有权操作的数据
  • 关键语句:
    • 授权:Grant privs On R to users [With Grant Option]
    • 撤销授权:Revoke privs On R From users [Cascade | Restrict]
  • 支持授权关系可视化(Grant diagram)

(二)数据完整性

1. 静态完整性约束
  • 基础约束类型:Primary Key(主键)、Foreign Key(外键)、Unique(唯一)、NOT NULL(非空)、Check(自定义检查)
  • 核心作用:防止数据录入错误(inserts)、保证更新操作正确性(updates)、维护数据一致性、为数据库存储和查询提供数据规则
2. 动态完整性(触发器)
  • 核心逻辑:When event occurs, check condition; if true, do action(当事件触发时,检查条件,满足则执行操作)

  • 作用:将业务逻辑从应用程序迁移到 DBMS,增强约束表达能力,支持约束 "修复" 逻辑

  • SQL 标准语法:

    sql 复制代码
    Create Trigger name
    Before | After | Instead Of events
    [referencing-variables]
    [For Each Row]
    When (condition)
    action
  • 特殊应用:通过Instead of触发器实现视图的自定义修改

(三)视图相关

1. 普通视图作用
  • 数据隐藏:对不同用户隐藏敏感数据
  • 简化查询:使复杂查询更简洁、更符合自然逻辑
  • 访问模块化:规范数据库访问方式
2. 物化视图(Materialized Views)
  • 继承普通视图全部作用
  • 额外优势:类似索引,可显著提高查询效率
3. SQL 标准可更新视图(updatable views)定义
  • 基于单个表 T 的查询(无Distinct
  • 视图中未包含的属性需允许为NULL或有默认值
  • 子查询不得引用表 T
  • Group by或聚合函数

二、PostgreSQL 扩展(11.1 节)

(一)PostgreSQL 服务器架构

  • 逻辑功能划分:三层结构(客户机→应用服务器→数据库服务器)
  • 核心优势:
    • 性能优化:数据直接在数据库内部访问,无需跨端传输
    • 易于维护:直接更新数据库服务器,无需修改客户端
    • 安全可控:仅授权用户访问函数,无法直接操作底层表

(二)PL/pgSQL 语言

1. 语言特性
  • 设计渊源:受 Oracle 的 PL/SQL 影响
  • 功能定位:功能强大的 SQL 脚本语言,虽 PostgreSQL 未明确称其为 "存储过程",但通过完整控制结构 + 触发器 + 运算符 + 索引支持,形成完整存储过程开发系统
  • 核心优点:易于上手、默认集成于大多数 PostgreSQL 部署、针对数据密集型任务优化性能
2. 语法规则
  • 块结构:[ <<label>> ] [ DECLARE declarations ] BEGIN statements END [label];
  • 结束符要求:变量申明和语句以分号;结尾,嵌套 block 的 END 后需加;(最后一个 END 除外)
  • 注释方式:单行注释--,多行注释/* */
  • 大小写规则:变量和关键词不区分大小写(字符 'A' 和字符串 "A" 除外)
  • 变量作用域:Block 内部可声明变量,同名变量覆盖外部变量,可通过label.variable访问外部变量
  • 变量声明语法:name [CONSTANT] type [COLLATE collation_name] [NOT NULL] [{DEFAULT | := | =} expression];

(三)自定义类型和操作符

1. 自定义类型创建
  • 语法示例(水果数量类型):CREATE TYPE FRUIT_QTY as (name text, qty int);
  • 类型转换:使用::符号,如'Point(10 20)'::geometry'(''APPLE'', 3)'::FRUIT_QTY
2. 自定义函数与操作符绑定
  • 步骤:先创建自定义比较函数,再将函数绑定为操作符

  • 示例(水果价值比较):

    sql 复制代码
    -- 自定义比较函数
    CREATE FUNCTION fruity_qty_larger_than(left_fruit FRUIT_QTY, right_fruit FRUIT_QTY) RETURNS BOOL AS $$ ... $$ LANGUAGE plpgsql;
    -- 绑定为>操作符
    CREATE OPERATOR > (leftarg = FRUIT_QTY, rightarg = FRUIT_QTY, procedure = fruit_qty_larger_than, commutator = >);
3. 扩展几何类型示例
sql 复制代码
Create Type Geometry As Object (
Private Dimension SmallInt Default -1,
Private CoordinateDimension SmallInt Default 2,
Private Is3D SmallInt Default 3,
Private IsMeasured SmallInt Default 0)
Not Instantiable
Not Final
  • 支持自定义方法(如Dimension()函数)和几何操作符(如&&:判断 2D 包围盒是否相交)

(四)定制排序方法和索引

1. 核心逻辑
  • 基于自定义函数实现特殊排序规则,再为该函数创建索引,优化查询性能
2. 示例(按元音逆向排序)
sql 复制代码
-- 自定义排序函数
CREATE OR REPLACE FUNCTION reversed_vowels(word text) RETURNS text AS $$ 
vowels = [c for c in word.lower() if c in 'aeiou'] 
vowels.reverse(); 
return ''.join(vowels); 
$$ LANGUAGE plpythonu IMMUTABLE;
-- 使用排序函数查询
Select word, reversed_vowels(word) from words order by reversed_vowels(word);
-- 创建索引优化性能
CREATE INDEX reversed_vowels_index ON words (reversed_vowels(word));

三、函数(11.2 节)

(一)函数结构

1. 核心元素
  • 组成部分:函数名、参数(变量名 + 类型名)、返回类型、函数主体、语言声明

  • 语法示例(笛卡尔距离计算):

    sql 复制代码
    create or replace function ST_P2PDistance(x1 float, y1 float, x2 float, y2 float) 
    returns float as $$ 
    begin 
    return sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1)); 
    end; 
    $$ language plpgsql;
2. 变量与数据访问
  • 变量声明:除参数外,所有变量需在DECLARE块中提前声明,仅在函数执行的 block 内有效
  • 数据赋值:支持SELECT select_expressions INTO target FROM ...语法(如转账函数中查询余额赋值)
  • 函数重载:支持同名函数不同参数列表(返回类型不同不构成重载),如mid(str varchar, start integer)mid(str varchar, start integer, end integer)

(二)条件表达式

1. IF/THEN/ELSE 语句
sql 复制代码
IF boolean-expression THEN 
  statements 
[ ELSIF boolean-expression THEN 
  statements ...] 
[ ELSE 
  statements ] 
END IF;
  • 注意:赋值操作(= | :=)与相等判断(=)的语法区别
  • 简化示例:IF(trim(firstname) = '', NULL, firstname)
2. CASE 语句
sql 复制代码
CASE search-expression 
WHEN expression [, expression [ ... ]] THEN 
  statements 
[ WHEN expression [, expression [ ... ]] THEN 
  statements ... ] 
[ ELSE 
  statements ] 
END CASE;
  • 示例:

    sql 复制代码
    CASE x 
    WHEN 1, 2 THEN 
      msg := 'one or two'; 
    ELSE
      msg := 'other value than one or two'; 
    END CASE;

(三)循环表达式

1. 基础循环类型
  • LOOP 循环:支持CONTINUE(跳过当前迭代)、EXIT(终止循环,等效于 break)

    sql 复制代码
    LOOP
      count := count + 1; 
      CONTINUE WHEN count < 0; 
      EXIT WHEN count > 100; 
    END LOOP;
  • WHILE 循环:count := 0; WHILE count <= 100 LOOP count := count + 1; END LOOP;

  • FOR 循环:

    • 数值循环:FOR i IN 1...100 LOOP END LOOP;(支持REVERSE反向、BY指定步长)

    • 结果集循环:自动创建游标,遍历查询结果

      sql 复制代码
      DECLARE movie RECORD; 
      FOR movie IN SELECT * FROM movies LOOP 
        movie.id, movie.name... 
      END LOOP;
2. 特殊循环语句
  • EXECUTE 语句:动态构建 PL/pgSQL 命令字符串并执行,如EXECUTE 'TRUNCATE TABLE' || table_name
  • PERFORM 语句:执行语句并忽略结果(如记录日志),如PERFORM cs_log('Done refreshing materialized views');
3. 循环应用示例(斐波那契序列)
sql 复制代码
CREATE OR REPLACE FUNCTION fib(n integer) RETURNS decimal(1000, 0) AS $$ 
DECLARE 
  counter integer := 0; 
  a decimal(1000, 0) := 0; 
  b decimal(1000, 0) := 1; 
BEGIN 
  IF (n < 1) THEN RETURN 0; END IF; 
  LOOP 
    EXIT WHEN counter = n; 
    counter := counter + 1; 
    SELECT b, a+b INTO a, b; 
  END LOOP; 
  RETURN a; 
END; 
$$ LANGUAGE plpgsql;

(四)返回集合

1. 核心语法
  • 声明方式:RETURNS SETOF <类型>TABLE(...), RETURNS SETOF RECORD
  • 数据返回:使用RETURN NEXT(逐行返回)或RETURN QUERY(直接返回查询结果集)
2. 应用示例
  • 斐波那契序列集合返回:

    sql 复制代码
    CREATE OR REPLACE FUNCTION fib_seq(num integer) RETURNS SETOF integer AS $$ 
    DECLARE a int := 0; b int := 1; 
    BEGIN 
      IF (num < 1) THEN RETURN; END IF; 
      RETURN NEXT a; 
      LOOP 
        EXIT WHEN num <= 1; 
        RETURN NEXT b; 
        num := num - 1; 
        SELECT b, a+b INTO a, b; 
      END LOOP; 
    END; 
    $$ LANGUAGE plpgsql;
  • 查询系统已安装语言:

    sql 复制代码
    CREATE OR REPLACE FUNCTION installed_languages() RETURNS SETOF pg_language AS $$ 
    BEGIN 
      RETURN QUERY SELECT * FROM pg_language; 
    END; 
    $$ LANGUAGE plpgsql;
3. 返回集合类型总结
返回类型声明 RECORD 结构来源 函数内部实现方式
SETOF <type> 类型定义 声明 ROW/RECORD 变量,赋值后通过 RETURN NEXT 返回
SETOF <table/view> 对应表 / 视图结构 直接返回符合表 / 视图结构的结果集
SETOF RECORD(动态) 调用时通过 AS (名称 类型,...) 指定 动态构建结果集并返回
SETOF RECORD(OUT 参数) OUT/INOUT 函数参数 赋值给 OUT 变量,通过 RETURN NEXT 返回
TABLE(...) TABLE 关键字后括号内声明 转换为 OUT 变量,赋值后 RETURN NEXT 返回

(五)错误处理与异常

1. RAISE 语句
  • 语法:RAISE [level] 'format' [, expression [, ...]] [USING option = expression [, ...]];
  • 级别(level):DEBUG、LOG、INFO、NOTICE、WARNING、EXCEPTION(默认级别为 EXCEPTION)
  • 作用:
    • EXCEPTION:抛出错误并终止当前事务
    • NOTICE/INFO 等:输出提示信息(可在 pgAdmin 4 消息窗口查看)
  • 示例:RAISE NOTICE 'a = %, b = %, c = %', a, b, c;
2. 异常捕获
  • 语法结构:

    sql 复制代码
    BEGIN 
      SELECT * INTO STRICT myrec FROM emp WHERE empname = myname; 
    EXCEPTION 
      WHEN NO_DATA_FOUND THEN RAISE EXCEPTION 'employee % not found', myname; 
      WHEN TOO_MANY_ROWS THEN RAISE EXCEPTION 'employee % not unique', myname; 
    END;
  • 关键说明:STRICT关键字要求查询必须返回恰好一行数据,否则触发异常

3. 异常信息获取
  • 语法:GET STACKED DIAGNOSTICS variable {=|:=} item [, ...]

  • 常用异常信息项:

    名称 类型 描述
    RETURNED_SQLSTATE text 异常的 SQLSTATE 错误码
    MESSAGE_TEXT text 异常的主消息文本
    TABLE_NAME text 与异常相关的表名
    PG_EXCEPTION_DETAIL text 异常的详细消息文本(若有)
    PG_EXCEPTION_HINT text 异常的提示消息文本(若有)
4. FOUND 变量
  • 作用:标识 SQL 语句执行结果状态
  • 赋值规则:
    • SELECT INTO:返回行则设为 true,否则 false
    • PERFORM/UPDATE/INSERT/DELETE:影响至少一行则 true,否则 false
    • FETCH:返回行则 true,否则 false
    • FOR/FOREACH 循环:迭代至少一次则 true,否则 false
    • RETURN QUERY:查询返回至少一行则 true,否则 false

(六)几何函数应用举例

1. 折线顶点提取(ST_PointsFromLine)
  • 功能:提取折线(ST_LineString)的所有顶点,非线段类型返回空集
  • 核心逻辑:通过ST_NumPoints获取顶点数,循环使用ST_PointN提取顶点,最后用ST_Collect聚合为多点类型
2. 多边形内环数统计(ST_NInteriorRings)
  • 功能:统计单个多边形或多多边形(ST_MultiPolygon)的内环总数
  • 核心逻辑:多多边形时循环遍历每个子几何对象,累加内环数
3. 包围盒计算(ST_AABBEnvelope)
  • 功能:计算几何对象的轴对齐包围盒(AABB)
  • 核心逻辑:通过ST_DumpPoints拆分所有顶点,获取ST_X/ST_Y的最大最小值,用ST_MakeEnvelope构建包围盒
4. 交叠关系判断(ST_GeomOverlaps)
  • 交叠定义:两几何对象的内部维度相同,交集维度与内部维度相同,且交集不等于任一对象本身
  • 核心逻辑:通过ST_Intersection计算交集,验证维度和相等性条件
相关推荐
C语言魔术师2 小时前
【linux】linux进程概念(四)(环境变量)
linux·运维·服务器
松涛和鸣2 小时前
DAY32 Linux Thread Programming
linux·运维·数据库·算法·list
源代码•宸2 小时前
分布式缓存-GO(简历写法、常见面试题)
服务器·开发语言·经验分享·分布式·后端·缓存·golang
秦jh_2 小时前
【Qt】常用控件(上)
服务器·数据库·qt
爬山算法3 小时前
Netty(14)如何处理Netty中的异常和错误?
java·前端·数据库
云和数据.ChenGuang3 小时前
自动化运维工程师之ansible启动rpcbind和nfs服务
运维·服务器·运维技术·数据库运维工程师·运维教程
yimengsama3 小时前
VMWare虚拟机如何连接U盘
linux·运维·服务器·网络·windows·经验分享·远程工作
松涛和鸣3 小时前
32、Linux线程编程
linux·运维·服务器·c语言·开发语言·windows
꧁坚持很酷꧂3 小时前
把虚拟机Ubuntu中的USB设备名称改为固定名称
linux·数据库·ubuntu