当前位置: 代码网 > it编程>数据库>Mysql > MySQL空间函数及记录经纬度并进行计算详解

MySQL空间函数及记录经纬度并进行计算详解

2026年01月25日 Mysql 我要评论
一、空间数据类型在 mysql 空间数据类型中,geometry 是所有空间类型的“基类”,其余(point、linestring 等)都是 geometry 的具体子类,用于

一、空间数据类型

在 mysql 空间数据类型中,geometry 是所有空间类型的“基类”,其余(point、linestring 等)都是 geometry 的具体子类,用于存储不同形态的地理/几何信息(如单个点、线、区域、多个点集合等)。这些类型的核心作用是结构化存储空间数据,配合空间函数(如距离计算、范围判断)和空间索引,实现高效的地理/几何运算。

1、geometry:核心基类

作用:

所有空间数据类型的父类型(抽象基类),本身不直接存储具体的空间形态,而是用于:

1.兼容所有子类(如 point、polygon 都可赋值给 geometry 类型字段);

2.统一处理混合类型的空间数据(如查询时返回任意类型的空间结果)。

关键特点:

不能直接用 insert 插入数据(无具体形态),需通过子类的 wkt/函数生成后赋值;

支持所有空间函数(如 st_srid()st_astext()),可接收任意子类的空间对象。

适用场景:

需存储“不确定形态”的空间数据(如同时存储点、线、面);

通用化的空间数据接口(如函数参数、存储过程返回值)。

-- 定义 geometry 类型字段(兼容所有空间类型)
create table spatial_data (
  id int primary key auto_increment,
  geom geometry not null srid 4326 comment '兼容任意空间类型'
);

-- 插入 point 类型数据(自动兼容 geometry 字段)
insert into spatial_data (geom) values (st_makepoint(116.4, 39.9));

-- 插入 polygon 类型数据(同样兼容)
insert into spatial_data (geom) values (
  st_geomfromtext('polygon((116.3 39.8, 116.5 39.8, 116.5 40.0, 116.3 40.0, 116.3 39.8))', 4326)
);

2、point:单个点(重要)

作用:

存储二维平面/地球表面的单个坐标点(核心用于经纬度、具体位置)。

关键特点:

由一对坐标 (x, y) 组成(地理场景:x=经度,y=纬度);

必须指定 srid(如 4326 对应 wgs84 经纬度);

是经纬度存储的最优类型(之前对话重点讲过)。

实际场景:

存储 poi 坐标(如商场、景点、地址);

设备定位点(如手机gps、车辆定位)。

-- wkt 格式:point(x y)(经度在前,纬度在后  貌似我的版本正好是反过来的?很奇怪)
st_geomfromtext('point(116.4042 39.9153)', 4326)

-- 简化函数(mysql 8.0.12+):st_makepoint(x, y)(自动继承字段 srid)
st_makepoint(116.4042, 39.9153)

3、linestring:线串(折线)

作用:

存储由多个有序点连接而成的连续线段(可理解为“折线”,非曲线)。

关键特点:

由 2 个及以上 point 组成(点的顺序决定线的走向);

点之间是直线连接,可自交(但通常用于无自交的连续线);

坐标单位与 srid 一致(4326 为度,3857 为米)。

实际场景:

道路、铁路、航线(如公交路线、飞机航线);

河流、管道、边界线(如省界的一段);

轨迹(如跑步路线、车辆行驶轨迹)。

-- wkt 格式:linestring(点1 点2 点3 ...)(点之间用空格分隔)
-- 示例:北京到天津的航线(简化为3个途经点)
st_geomfromtext('linestring(116.4042 39.9153, 116.8 39.95, 117.2 39.13)', 4326)

4、polygon:多边形(闭合区域)

作用:

存储由闭合线串围成的区域(可包含“孔洞”),用于表示“面状”地理范围。

关键特点:

核心是“闭合线串”:外边界的首尾点必须完全相同(否则 mysql 会自动补全,但不推荐);

支持“孔洞”:可包含多个线串,第一个是外边界,后续是内边界(孔洞,如区域内的湖泊);

点的顺序:外边界按“顺时针”或“逆时针”排列,内边界(孔洞)顺序相反(避免交叉)。

实际场景:

行政区域(如城市、区县、省份范围);

地块、园区(如工业园区、校园范围);

地理围栏(如“电子围栏内的设备报警”)。

-- 1. 简单多边形(无孔洞):北京市东城区范围(简化)
st_geomfromtext('polygon((116.35 39.88, 116.45 39.88, 116.45 39.95, 116.35 39.95, 116.35 39.88))', 4326)

-- 2. 带孔洞的多边形(区域内有湖泊)
st_geomfromtext('polygon(
  (116.35 39.88, 116.45 39.88, 116.45 39.95, 116.35 39.95, 116.35 39.88),  -- 外边界
  (116.38 39.90, 116.42 39.90, 116.42 39.93, 116.38 39.93, 116.38 39.90)   -- 内边界(孔洞)
)', 4326)

5、复合类型(multi 开头):多个同类型几何对象

用于存储多个结构相同的空间对象(如多个点、多条线、多个多边形),且这些对象之间相互独立、不重叠(逻辑上是“集合”)。

6、multipoint:多点集合

作用:

存储多个独立的 point(无关联,不连接)。

关键特点:

多个点之间无顺序要求,互不连接;

适合存储“一组离散的点”(无需每条记录存一个 point)。

实际场景:

多个poi集合(如同一品牌的所有门店坐标);

传感器部署点、监测点(如多个空气质量监测站)。

-- 示例:某城市的多个公交站点坐标
st_geomfromtext('multipoint((116.40 39.91), (116.41 39.92), (116.42 39.90), (116.39 39.93))', 4326)

7、multilinestring:多线集合

作用:

存储多条独立的 linestring(互不连接,无顺序要求)。

关键特点:

每条线串都是独立的(如多条不相交的道路);

避免重复创建多条 linestring 记录,简化数据管理。

实际场景:

多条道路、水系(如一个区域内的所有河流);

多条航线、轨迹(如某航空公司的多条航线)。

-- 示例:某城市的3条主要道路
st_geomfromtext('multilinestring(
  (116.35 39.88, 116.45 39.88),  -- 道路1(东西向)
  (116.40 39.88, 116.40 39.95),  -- 道路2(南北向)
  (116.38 39.90, 116.42 39.93)   -- 道路3(斜向)
)', 4326)

8、multipolygon:多面集合

作用:

存储多个独立的 polygon(互不重叠、不相交)。

关键特点:

每个多边形都是独立的(如多个城市、多个地块);

适合存储“一组区域”(如省份包含的所有区县)。

实际场景:

行政区域集合(如省份、国家包含的所有下级区域);

多个地块、园区(如一个开发区内的多个工厂地块)。

-- 示例:京津冀地区的3个主要城市范围(简化)
st_geomfromtext('multipolygon(
  -- 北京
  ((116.3 39.8, 116.6 39.8, 116.6 40.1, 116.3 40.1, 116.3 39.8)),
  -- 天津
  ((117.1 39.0, 117.4 39.0, 117.4 39.3, 117.1 39.3, 117.1 39.0)),
  -- 石家庄
  ((114.2 38.0, 114.6 38.0, 114.6 38.4, 114.2 38.4, 114.2 38.0))
)', 4326)

9、混合集合:geometrycollection

作用:

存储多种不同类型的空间对象(如 point + linestring + polygon),是最灵活的空间类型(但使用频率较低)。

关键特点:

可包含任意空间类型(单个或复合类型),如“一个点 + 一条线 + 一个多边形”;

无类型限制,但可读性和查询效率较低(不推荐频繁使用);

需确保所有对象的 srid 一致(否则空间函数会报错)。

实际场景:

复杂地理数据集(如一个区域内的所有地理要素:点、线、面);

临时数据存储(如批量导入的混合类型空间数据)。

-- 示例:某区域的“景点(点)+ 游览路线(线)+ 景区范围(面)”
st_geomfromtext('geometrycollection(
  point(116.4042 39.9153),  -- 天安门(点)
  linestring(116.40 39.91, 116.41 39.92),  -- 游览路线(线)
  polygon((116.39 39.90, 116.42 39.90, 116.42 39.93, 116.39 39.93, 116.39 39.90))  -- 景区范围(面)
)', 4326)

二、使用

1、point相关

(1)建表与索引

create table `poi` (
  `id` int primary key auto_increment comment '主键id',
  `name` varchar(100) not null comment '地点名称',
  `location` point srid 4326 not null comment '经纬度(point类型,wgs84坐标系)',
  `address` varchar(255) comment '详细地址',
  -- 创建空间索引(加速空间查询)
  spatial index `idx_spatial_location` (`location`)
) engine=innodb default charset=utf8mb4 comment='poi地点表';

(2)st_pointfromtext():从 wkt 构造点(推荐,显式指定 srid)

-- 语法:st_pointfromtext('point(纬度 经度)', srid)
insert into poi (name, location, address)
values (
  '天安门',
  st_pointfromtext('point(39.914885 116.403874)', 4326), -- 经度116.403874,纬度39.914885
  '北京市东城区东长安街'
), (
  '上海外滩',
  st_pointfromtext('point(31.235924 121.490171)', 4326), -- 经度121.490171,纬度31.235924
  '上海市黄浦区中山东一路'
);

(3)st_geomfromtext():通用几何对象创建函数

insert into poi (name, location, address)
values (
  '广州塔',
  st_geomfromtext('point(23.113500 113.330430)', 4326),
  '广州市海珠区阅江西路222号'
);

(4)st_srid():通过对象创建

insert into poi (name, location, address)
values (
  '深圳市民中心',
  st_srid(point(114.057865, 22.543096), 4326), -- point(经度, 纬度)
  '深圳市福田区福中三路'
);

(5)st_x、st_y查询x、y坐标(不适用经纬度)

mysql> select st_x(point(56.7, 53.34));
+--------------------------+
| st_x(point(56.7, 53.34)) |
+--------------------------+
|                     56.7 |
+--------------------------+
mysql> select st_y(point(56.7, 53.34));
+--------------------------+
| st_y(point(56.7, 53.34)) |
+--------------------------+
|                    53.34 |
+--------------------------+

(6)st_astext(), st_aswkt():转换为字符串、wkt格式

mysql> set @g = 'linestring(1 1,2 2,3 3)';
mysql> select st_astext(st_geomfromtext(@g));
+--------------------------------+
| st_astext(st_geomfromtext(@g)) |
+--------------------------------+
| linestring(1 1,2 2,3 3)        |
+--------------------------------+

(7)st_longitude()、st_latitude():查询经纬度

select
  id,
  name,
  st_longitude(location) as longitude, -- 提取经度
  st_latitude(location) as latitude,  -- 提取纬度
  address
from poi;

(8)st_distance():点的平面距离(不适用经纬度)

mysql> set @g1 = st_geomfromtext('point(1 1)');
mysql> set @g2 = st_geomfromtext('point(2 2)');
mysql> select st_distance(@g1, @g2);
+-----------------------+
| st_distance(@g1, @g2) |
+-----------------------+
|    1.4142135623730951 |
+-----------------------+

mysql> set @g1 = st_geomfromtext('point(1 1)', 4326);
mysql> set @g2 = st_geomfromtext('point(2 2)', 4326);
mysql> select st_distance(@g1, @g2);
+-----------------------+
| st_distance(@g1, @g2) |
+-----------------------+
|     156874.3859490455 |
+-----------------------+
mysql> select st_distance(@g1, @g2, 'metre');
+--------------------------------+
| st_distance(@g1, @g2, 'metre') |
+--------------------------------+
|              156874.3859490455 |
+--------------------------------+
mysql> select st_distance(@g1, @g2, 'foot');
+-------------------------------+
| st_distance(@g1, @g2, 'foot') |
+-------------------------------+
|             514679.7439273146 |
+-------------------------------+

(9)st_distance_sphere():基于球体(地球)计算两点直线距离

select
  st_distance_sphere ( st_pointfromtext ( 'point(39.914885 116.403874)', 4326 ), st_pointfromtext ( 'point(31.235924 121.490171)', 4326 ) ) as distance_m;

2、实战

(1)查询范围内的点

-- 步骤1:构造目标点(天安门经纬度)
-- 步骤2:计算每个poi到目标点的距离(米)
-- 步骤3:筛选距离≤5000米的结果,按距离升序排序
select
  id,
  name,
  address,
  st_longitude(location) as longitude,
  st_latitude(location) as latitude,
  -- 计算距离(米),保留2位小数
  round(st_distance_sphere(
    location,
    st_pointfromtext('point(39.914883 116.403873)', 4326) -- 目标点:天安门
  ), 2) as distance_m
from poi
where
  -- 先通过经纬度范围粗筛(减少计算量,优化性能)
  st_longitude(location) between 116.403872 - 0.05 and 116.403874 + 0.05 -- 经度范围(≈5.5公里)
  and st_latitude(location) between 39.914883 - 0.05 and 39.914885 + 0.05 -- 纬度范围(≈5.5公里)
  -- 再精确筛选5公里内
  and st_distance_sphere(
    location,
    st_pointfromtext('point(39.914885 116.403874)', 4326)
  ) < 5000
order by distance_m asc; -- 按距离从近到远排序

参考资料

https://dev.mysql.com/doc/refman/8.0/en/spatial-types.html
https://dev.mysql.com/doc/refman/8.0/en/spatial-function-reference.html

到此这篇关于mysql空间函数及记录经纬度并进行计算的文章就介绍到这了,更多相关mysql空间函数记录经纬度内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2026  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com