news 2026/4/16 12:06:07

第十一章中的函数解读(1)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
第十一章中的函数解读(1)

第一个函数

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;

第一行:函数定义

create or replace function ST_P2PDistance(x1 float, y1 float, x2 float, y2 float)
  • create or replace function: 创建或替换函数

    • 如果函数不存在,则创建新函数

    • 如果同名函数已存在,则替换它

  • ST_P2PDistance: 函数名

    • ST_前缀:遵循空间函数命名约定(SQL/MM标准)

    • P2P:Point to Point(点到点)

    • Distance:表示这是计算距离的函数

  • (x1 float, y1 float, x2 float, y2 float): 参数列表

    • 四个浮点数参数:第一个点的x,y坐标,第二个点的x,y坐标

    • x1, y1: 第一个点的坐标

    • x2, y2: 第二个点的坐标

    • float: 参数类型,浮点数

第二行:返回值声明

returns float as $$
  • returns float: 声明函数返回一个浮点数

    • 计算结果是两点之间的欧几里得距离

  • as $$: 开始函数体

    • $$是"美元符号引用",用于定义函数体的开始和结束

    • 这是PostgreSQL中定义多行字符串的常用方式

    • 也可以使用单引号,但$$更方便(无需转义内部引号)

第三行:函数体开始

begin
  • begin: 标记PL/pgSQL函数体的开始

    • PL/pgSQL是PostgreSQL的过程化语言扩展

    • 所有PL/pgSQL函数都以begin开始

第四行:计算逻辑

return sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));

这是函数的核心计算逻辑

计算过程分解:

  1. (x2 - x1) * (x2 - x1): 计算x坐标差的平方

    • (x2 - x1): 两点在x轴上的距离

    • 乘以自身:得到平方,确保值为正

  2. (y2 - y1) * (y2 - y1): 计算y坐标差的平方

    • (y2 - y1): 两点在y轴上的距离

    • 乘以自身:得到平方

  3. 相加:(x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1)

    • 根据勾股定理:斜边² = 直角边1² + 直角边2²

    • 这里得到的是两点间直线距离的平方

  4. sqrt(...): 计算平方根

    • 将平方和开方,得到实际的直线距离

    • sqrt()是PostgreSQL内置的数学函数

数学公式

距离=(x2−x1)2+(y2−y1)2距离=(x2​−x1​)2+(y2​−y1​)2​

第五行:函数体结束

end;
  • end: 标记PL/pgSQL函数体的结束 与begin配对使用

第六行:语言声明

$$ language plpgsql;
  • $$: 结束函数体的"美元符号引用"

    • 与第二行的$$配对

  • language plpgsql: 声明函数使用PL/pgSQL语言编写

    • PostgreSQL支持多种函数语言:SQL、PL/pgSQL、Python等

    • PL/pgSQL是专门为PostgreSQL设计的过程化语言

完整示例:如何使用这个函数

-- 示例1:计算点(0,0)和点(3,4)之间的距离 SELECT ST_P2PDistance(0, 0, 3, 4); -- 返回:5.0 (因为3²+4²=9+16=25,√25=5) -- 示例2:在查询中使用 SELECT city1, city2, ST_P2PDistance(x1, y1, x2, y2) as distance_km FROM city_pairs;

重要说明:

1. 坐标系假设

这个函数假设:

  • 使用平面直角坐标系(欧几里得几何)

  • 不适用于地理坐标系(经纬度)

    • 对于经纬度坐标,需要使用球面距离公式(如Haversine公式)

    • 或者在GEOGRAPHY类型上使用ST_Distance()函数

2. 与SQL Server Spatial的区别

在SQL Server Spatial中,相同功能可以通过以下方式实现:

-- SQL Server Geometry类型 DECLARE @p1 geometry = geometry::Point(x1, y1, 0); DECLARE @p2 geometry = geometry::Point(x2, y2, 0); SELECT @p1.STDistance(@p2); -- 或者使用内置函数 SELECT geometry::Point(x1, y1, 0).STDistance(geometry::Point(x2, y2, 0));

3. 可能的改进

-- 改进版:添加参数验证和注释 CREATE OR REPLACE FUNCTION ST_P2PDistance( x1 float, y1 float, x2 float, y2 float ) RETURNS float AS $$ DECLARE dx float; dy float; BEGIN -- 计算坐标差 dx := x2 - x1; dy := y2 - y1; -- 返回欧几里得距离 RETURN sqrt(dx * dx + dy * dy); END; $$ LANGUAGE plpgsql IMMUTABLE -- 表示函数是幂等的(相同输入总是相同输出) STRICT -- 如果任何参数为NULL,则返回NULL PARALLEL SAFE; -- 可以安全地并行执行

这个函数是一个简单的欧几里得距离计算器,适用于平面坐标系中的两点距离计算。

第二个函数

-- 自定义比较函数 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 = >);

第一部分:自定义比较函数定义

-- 自定义比较函数
  • 这是一个注释,说明接下来要创建自定义比较函数

  • --是 SQL 的单行注释符号

CREATE FUNCTION fruity_qty_larger_than(left_fruit FRUIT_QTY, right_fruit FRUIT_QTY) RETURNS BOOL AS $$ ... $$ LANGUAGE plpgsql;

函数声明部分:

CREATE FUNCTION fruity_qty_larger_than

  • CREATE FUNCTION:创建新函数的 SQL 命令

  • fruity_qty_larger_than:函数名称

    • 这是一个自定义命名,描述了函数的功能:"水果数量大于比较"

参数定义部分:

(left_fruit FRUIT_QTY, right_fruit FRUIT_QTY)

  • 参数列表,定义两个输入参数:

    • left_fruit:第一个参数名,代表比较操作符左边的操作数

    • right_fruit:第二个参数名,代表比较操作符右边的操作数

    • FRUIT_QTY:两个参数的类型

      • 这是一个用户自定义的复合类型(如之前的CREATE TYPE FRUIT_QTY定义)

      • 可能包含类似(fruit_name TEXT, quantity INT)这样的字段

返回类型:

RETURNS BOOL

  • 指定函数返回布尔值TRUEFALSE

  • 表示比较结果:真(大于)或假(不大于)

函数体占位符:

AS $$ ... $$

  • $$ ... $$:美元符号引用的函数体

  • ...:这里是占位符,表示实际的函数实现代码被省略了

  • 实际的实现可能类似于:

    AS $$ BEGIN -- 比较逻辑,比如: -- 1. 先比较 quantity 字段 -- 2. 如果 quantity 相等,再按 fruit_name 排序 IF left_fruit.quantity > right_fruit.quantity THEN RETURN TRUE; ELSIF left_fruit.quantity < right_fruit.quantity THEN RETURN FALSE; ELSE -- quantity相等时,按fruit_name比较 RETURN left_fruit.fruit_name > right_fruit.fruit_name; END IF; END; $$

语言声明:

LANGUAGE plpgsql;

  • 指定函数用PL/pgSQL语言编写

  • PostgreSQL 支持多种过程化语言


第二部分:操作符绑定

CREATE OPERATOR > (leftarg = FRUIT_QTY, rightarg = FRUIT_QTY, procedure = fruit_qty_larger_than, commutator = >);

操作符创建:

CREATE OPERATOR >

  • CREATE OPERATOR:创建新操作符的命令

  • >:要创建/定义的操作符符号

    • 这是标准的"大于"比较操作符

    • PostgreSQL 允许为用户自定义类型重载现有操作符

操作符属性定义:

(leftarg = FRUIT_QTY, rightarg = FRUIT_QTY, ...)

  • leftarg = FRUIT_QTY:指定左操作数的类型为FRUIT_QTY

  • rightarg = FRUIT_QTY:指定右操作数的类型为FRUIT_QTY

  • 这意味着这个>操作符将用于比较两个FRUIT_QTY类型的值

procedure = fruit_qty_larger_than

  • 关键连接:指定当使用>操作符时,实际调用的函数

  • fruit_qty_larger_than:前面定义的函数名

    • 注意:这里写的是fruit_qty_larger_than(单数),而前面函数是fruity_qty_larger_than(复数)

    • 这可能是个笔误,或者故意使用不同名称(但通常应该一致)

    • 如果名称不匹配,创建操作符时会报错

commutator = >
  • 交换子声明:这是一个高级优化属性

  • commutator:指定该操作符的交换操作符

  • =:这里设置为自身>,表示:

    • 如果a > b为真,那么b < a也应该为真

    • PostgreSQL 查询优化器可以利用这个信息:

      • 当看到b < a时,知道可以转换为a > b

      • 可能利用索引或优化查询计划

  • 实际上,对于>操作符,其交换子应该是<

    -- 更正确的写法可能是: CREATE OPERATOR > (..., commutator = <); -- 并且还需要定义对应的 < 操作符: CREATE FUNCTION fruity_qty_smaller_than(left FRUIT_QTY, right FRUIT_QTY) RETURNS BOOL AS $$ ... $$; CREATE OPERATOR < (leftarg = FRUIT_QTY, rightarg = FRUIT_QTY, procedure = fruity_qty_smaller_than, commutator = >);

完整示例:实际使用场景

-- 1. 首先定义复合类型 CREATE TYPE FRUIT_QTY AS ( fruit_name TEXT, quantity INT ); -- 2. 实际函数实现(非占位符) CREATE FUNCTION fruity_qty_larger_than(left_fruit FRUIT_QTY, right_fruit FRUIT_QTY) RETURNS BOOL AS $$ BEGIN -- 主要按数量比较,数量相同则按名称字典序比较 IF left_fruit.quantity > right_fruit.quantity THEN RETURN TRUE; ELSIF left_fruit.quantity < right_fruit.quantity THEN RETURN FALSE; ELSE -- quantity相等时,比较fruit_name RETURN left_fruit.fruit_name > right_fruit.fruit_name; END IF; END; $$ LANGUAGE plpgsql; -- 3. 创建操作符(修正函数名一致) CREATE OPERATOR > ( leftarg = FRUIT_QTY, rightarg = FRUIT_QTY, procedure = fruity_qty_larger_than, -- 这里名称必须与函数名一致 commutator = > -- 实际上可能需要先定义 < 操作符 ); -- 4. 使用示例 SELECT (('apple', 10)::FRUIT_QTY) > (('banana', 5)::FRUIT_QTY) as result; -- 返回: TRUE (因为10 > 5) SELECT (('apple', 5)::FRUIT_QTY) > (('banana', 5)::FRUIT_QTY) as result; -- 返回: FALSE (因为数量相等,但'apple' < 'banana'字典序)

重要概念总结:

  1. 操作符重载:为自定义类型定义现有操作符(如>,<,=,+等)的行为

  2. 复合类型比较:定义如何比较包含多个字段的复合类型

  3. 操作符优化:通过commutatornegator等属性帮助查询优化器

  4. 类型安全性:确保操作符只能用于指定的类型组合

这种机制使得用户自定义类型可以像内置类型一样使用标准的 SQL 操作符,提供更自然、更符合直觉的查询语法。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/2 15:39:58

PyTorch-CUDA基础镜像安装指南:Ubuntu下GPU环境一键部署教程

PyTorch-CUDA基础镜像安装指南&#xff1a;Ubuntu下GPU环境一键部署教程 在深度学习项目开发中&#xff0c;最让人头疼的往往不是模型设计或调参&#xff0c;而是环境配置——“为什么代码在他机器上跑得好好的&#xff0c;在我这却报CUDA错误&#xff1f;”这种问题几乎每个A…

作者头像 李华
网站建设 2026/4/15 23:21:40

轻量化多模态模型Qwen3-VL-8B在内容审核中的应用探索

轻量化多模态模型Qwen3-VL-8B在内容审核中的应用探索 在社交媒体日均产生数十亿条图文内容的今天&#xff0c;传统基于关键词和单一模态的审核方式早已捉襟见肘。一张看似普通的风景照配上“内部渠道&#xff0c;速来领取”的文案&#xff0c;可能暗藏诈骗诱导&#xff1b;一段…

作者头像 李华
网站建设 2026/4/14 2:27:29

LeetCode hot 100 —— 双指针(面试纯背版)(二)

双指针 1、移动零 给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。 请注意 ,必须在不复制数组的情况下原地对数组进行操作。 示例 1: 输入: nums = [0,1,0,3,12] 输出: [1,3,12,0,0] 示例 2: 输入: nums = [0] 输出: [0] 提…

作者头像 李华
网站建设 2026/4/14 15:59:42

Diskinfo下载官网未提及的GPU监控技巧配合Qwen3-VL-8B使用

Diskinfo未提及的GPU监控技巧与Qwen3-VL-8B实战部署 在智能客服、电商图文理解等场景中&#xff0c;越来越多的产品开始集成“看图说话”能力。一个典型的挑战是&#xff1a;模型明明测试时运行良好&#xff0c;上线后却频繁崩溃——原因往往不是代码逻辑问题&#xff0c;而是G…

作者头像 李华