Skip to content

Commit db2e6cf

Browse files
committed
oracle通过经纬度过滤范围内数据
1 parent 1332bb1 commit db2e6cf

1 file changed

Lines changed: 304 additions & 0 deletions

File tree

Lines changed: 304 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,304 @@
1+
---
2+
layout: post
3+
title: oracle通过经纬度过滤范围内数据
4+
date: 2025-03-26 10:54:15
5+
tags:
6+
- oracle
7+
- 经纬度
8+
- 地图
9+
- WGS84坐标系
10+
categories:
11+
- 编程记录
12+
---
13+
14+
## Start
15+
16+
今天的需求是在地图上撒了很多点,右击这个点时,可以选择一个半径,呈现在这个半径范围内的点。
17+
和之前一个在地图上框选多边形区域的需求一样,需要通过经纬度来计算过滤数据。
18+
19+
这里是通过 Oracle 的空间运算符实现的。
20+
主要使用下面两个:
21+
22+
1. [SDO_WITHIN_DISTANCE](https://docs.oracle.com/en/database/oracle/oracle-database/23/spatl/sdo_within_distance.html)
23+
Identifies the set of spatial objects that are within some specified distance of a given object, such as an area of interest or point of interest.
24+
标识位于给定对象(如感兴趣区域或感兴趣点)的某个指定距离内的空间对象集。
25+
2. [SDO_INSIDE](https://docs.oracle.com/en/database/oracle/oracle-database/23/spatl/sdo_inside.html)
26+
Checks if any geometries in a table have the INSIDE topological relationship with a specified geometry. Equivalent to specifying the SDO_RELATE operator with 'mask=INSIDE'.
27+
检查表中的任何几何是否与指定几何具有 INSIDE 拓扑关系。等效于使用 'mask=INSIDE' 指定 SDO_RELATE 运算符。
28+
29+
## 需求实现
30+
31+
首先需要确保表中有经纬度的字段和数据,并且不为空。
32+
33+
~~~oraclesqlplus
34+
delete
35+
from T_GIS
36+
where LONGITUDE is null
37+
or LATITUDE is null;
38+
~~~
39+
40+
然后需要新建一个字段,为存储空间类型。存储经纬度转换后的数据。
41+
42+
~~~oraclesqlplus
43+
alter table T_GIS
44+
add POINT_GEOMETRY SDO_GEOMETRY
45+
~~~
46+
47+
将转换后的经纬度存储到这个字段中。
48+
49+
~~~oraclesqlplus
50+
UPDATE T_GIS a
51+
SET a.POINT_GEOMETRY = SDO_GEOMETRY(
52+
2001, -- 点类型
53+
8307, -- WGS84 坐标系
54+
SDO_POINT_TYPE(a.LONGITUDE, a.LATITUDE, NULL), -- 点坐标
55+
NULL, -- 无元素信息
56+
NULL -- 无坐标数组
57+
)
58+
where LONGITUDE is not null
59+
and LATITUDE is not null;
60+
~~~
61+
62+
然后需要为这个字段创建空间索引。
63+
64+
~~~oraclesqlplus
65+
DROP INDEX T_GIS_SPATIAL_IDX;
66+
67+
CREATE INDEX T_GIS_SPATIAL_IDX
68+
ON T_GIS (POINT_GEOMETRY)
69+
INDEXTYPE IS MDSYS.SPATIAL_INDEX;
70+
~~~
71+
72+
然后就可以使用 SDO_WITHIN_DISTANCE 来查询了。
73+
74+
~~~oraclesqlplus
75+
select *
76+
from T_GIS a
77+
where a.POINT_GEOMETRY is not null
78+
and a.LONGITUDE is not null
79+
and a.LATITUDE is not null
80+
and SDO_WITHIN_DISTANCE(
81+
a.POINT_GEOMETRY,
82+
SDO_GEOMETRY(
83+
2001, -- 点类型
84+
8307, -- WGS84 坐标系
85+
SDO_POINT_TYPE(104.48060937499996, 36.30556423523153, NULL), -- 点坐标 (经度, 纬度, 高度)
86+
NULL, -- 无元素信息
87+
NULL -- 无坐标数组
88+
),
89+
'DISTANCE=1000'
90+
) = 'TRUE';
91+
~~~
92+
93+
如果报错,可以使用下面的语句查看异常数据:
94+
95+
~~~oraclesqlplus
96+
SELECT *
97+
FROM T_GIS
98+
WHERE SDO_GEOM.VALIDATE_GEOMETRY_WITH_CONTEXT(POINT_GEOMETRY, 0.005) != 'TRUE';
99+
~~~
100+
101+
## WGS84 坐标系
102+
103+
WGS84(**World Geodetic System 1984**)是目前全球最广泛使用的 **大地坐标系(Geodetic Coordinate System)**,由美国国防部(DoD)制定,用于 **GPS 定位、地图绘制、GIS 系统** 等场景。
104+
105+
- WGS84 是一个 **地球参考坐标系**,用于描述地球表面点的位置(经度、纬度、高程)。
106+
- 它基于 **椭球体模型**(参考椭球),并定义了地球的形状、大小和重力场。
107+
108+
### 核心参数
109+
110+
| 参数 || 说明 |
111+
|-----------------|--------------------------|-------------------|
112+
| **椭球体长半轴(a)** | 6,378,137 米 | 赤道半径 |
113+
| **椭球体短半轴(b)** | 6,356,752.3142 米 | 极半径 |
114+
| **扁率(f)** | 1/298.257223563 | `f = (a - b) / a` |
115+
| **第一偏心率平方(e²)** | 0.00669437999014 | 用于坐标转换 |
116+
| **地球自转角速度(ω)** | 7.292115 × 10⁻⁵ rad/s | 影响重力场计算 |
117+
| **地心引力常数(GM)** | 3.986004418 × 10¹⁴ m³/s² | 用于卫星轨道计算 |
118+
119+
### 坐标表示
120+
WGS84 使用 **经度(Longitude)、纬度(Latitude)、高程(Height)** 表示位置:
121+
122+
- **经度(λ)**:东经(0°~180°E)或西经(0°~180°W)。
123+
- **纬度(φ)**:北纬(0°~90°N)或南纬(0°~90°S)。
124+
- **高程(h)**:相对于 WGS84 椭球面的高度(单位:米)。
125+
126+
### WGS84 的常见用途
127+
128+
1. GPS 定位
129+
- 全球定位系统(GPS)默认使用 WGS84 坐标系。
130+
- 手机、车载导航、无人机等设备的定位数据通常基于 WGS84。
131+
2. 地图服务
132+
- **Google Maps、百度地图、高德地图** 等在线地图的底层数据采用 WGS84。
133+
- 但部分地图(如中国 GCJ-02)会对 WGS84 进行加密偏移。
134+
3. GIS 和空间数据库
135+
- **Oracle Spatial、PostGIS、ArcGIS** 等支持 WGS84 坐标系。
136+
- 在 Oracle 中,WGS84 的 SRID(空间参考 ID)通常为:
137+
- **4326**(标准 WGS84,经纬度顺序:纬度, 经度)
138+
- **8307**(WGS84,经纬度顺序:经度, 纬度)
139+
140+
### WGS84 与其他坐标系的区别
141+
142+
WGS84 是全通通用的、无偏移的 GPS 原始数据,美国标准。GPS、谷歌地图等使用。
143+
GCJ-02 对 WGS84 进行非线性偏移。在中国国内使用,高德地图、腾讯地图等使用。
144+
CGCS2000 是中国标准,中国官方测绘。
145+
146+
> 注:CGCS2000 和 WGS84 在 **厘米级精度** 下可以视为一致,但在高精度测量(如卫星定位)时需转换。
147+
148+
149+
## Oracle Spatial 函数(部分)
150+
151+
### SDO_GEOMETRY
152+
153+
SDO_GEOMETRY 是 Oracle Spatial 的核心数据类型,用于存储空间数据。
154+
155+
基本语法
156+
157+
~~~oraclesqlplus
158+
SDO_GEOMETRY(
159+
geometry_type NUMBER, -- 几何类型代码
160+
srid NUMBER, -- 空间参考系ID
161+
point SDO_POINT_TYPE,-- 点坐标(仅用于点类型)
162+
elem_info SDO_ELEM_INFO_ARRAY, -- 元素定义数组
163+
ordinates SDO_ORDINATE_ARRAY -- 坐标值数组
164+
)
165+
~~~
166+
167+
几何类型代码
168+
169+
| 代码 | 类型说明 |
170+
|------|--------|
171+
| 2001 ||
172+
| 2002 | 线 |
173+
| 2003 | 多边形 |
174+
| 2005 | 多点集合 |
175+
| 2006 | 多线集合 |
176+
| 2007 | 多多边形集合 |
177+
178+
创建点
179+
180+
~~~oraclesqlplus
181+
-- 创建WGS84坐标系的点(经度120.5,纬度30.2)
182+
SELECT SDO_GEOMETRY(
183+
2001, -- 点类型
184+
8307, -- WGS84坐标系SRID
185+
SDO_POINT_TYPE(120.5, 30.2, NULL), -- 经度,纬度,高程
186+
NULL,
187+
NULL
188+
) FROM dual;
189+
~~~
190+
191+
创建线
192+
193+
~~~oraclesqlplus
194+
-- 创建由三个点组成的线
195+
SELECT SDO_GEOMETRY(
196+
2002, -- 线类型
197+
8307,
198+
NULL,
199+
SDO_ELEM_INFO_ARRAY(1, 2, 1), -- 简单线
200+
SDO_ORDINATE_ARRAY(120,30, 121,31, 122,30) -- 三个点坐标
201+
) FROM dual;
202+
~~~
203+
204+
创建多边形
205+
206+
~~~oraclesqlplus
207+
-- 创建四边形(必须闭合)
208+
SELECT SDO_GEOMETRY(
209+
2003, -- 多边形类型
210+
8307,
211+
NULL,
212+
SDO_ELEM_INFO_ARRAY(1, 1003, 1), -- 外多边形
213+
SDO_ORDINATE_ARRAY(120,30, 121,30, 121,31, 120,31, 120,30) -- 闭合坐标
214+
) FROM dual;
215+
~~~
216+
217+
### SDO_WITHIN_DISTANCE 函数详解
218+
219+
用于查询在指定距离范围内的空间对象。
220+
221+
基本语法
222+
223+
~~~oraclesqlplus
224+
SDO_WITHIN_DISTANCE(
225+
geometry1 SDO_GEOMETRY, -- 要检查的几何对象
226+
geometry2 SDO_GEOMETRY, -- 参考几何对象
227+
params VARCHAR2 -- 距离参数
228+
) RETURN VARCHAR2;
229+
~~~
230+
231+
参数说明
232+
233+
- `params` 格式:`'distance=<数值> unit=<单位>'`
234+
- `distance`:距离值
235+
- `unit`:单位(默认为坐标系单位,WGS84为米)
236+
237+
查询某点1公里范围内的所有商店
238+
239+
~~~oraclesqlplus
240+
SELECT s.store_id, s.store_name
241+
FROM stores s
242+
WHERE SDO_WITHIN_DISTANCE(
243+
s.location, -- 商店位置字段
244+
SDO_GEOMETRY(2001, 8307, SDO_POINT_TYPE(120.5, 30.2, NULL), NULL, NULL), -- 中心点
245+
'distance=1000' -- 1公里范围内
246+
) = 'TRUE';
247+
~~~
248+
249+
查询某区域500米内的所有道路
250+
251+
~~~oraclesqlplus
252+
SELECT r.road_id, r.road_name
253+
FROM roads r, regions reg
254+
WHERE reg.region_id = 101
255+
AND SDO_WITHIN_DISTANCE(
256+
r.geom, -- 道路几何
257+
reg.geom, -- 区域几何
258+
'distance=500' -- 500米内
259+
) = 'TRUE';
260+
~~~
261+
262+
### SDO_INSIDE
263+
264+
用于判断一个几何对象是否完全包含在另一个几何对象内部。
265+
266+
基本语法
267+
268+
~~~oraclesqlplus
269+
SDO_INSIDE(
270+
geometry1 SDO_GEOMETRY, -- 要检查的几何对象
271+
geometry2 SDO_GEOMETRY, -- 容器几何对象
272+
tol NUMBER -- 容差
273+
) RETURN VARCHAR2;
274+
~~~
275+
276+
查询完全在某个区域内的所有建筑
277+
278+
~~~oraclesqlplus
279+
SELECT b.building_id, b.building_name
280+
FROM buildings b, city_zones z
281+
WHERE z.zone_id = 5
282+
AND SDO_INSIDE(
283+
b.geometry, -- 建筑几何
284+
z.geometry, -- 区域几何
285+
0.05 -- 容差
286+
) = 'TRUE';
287+
~~~
288+
289+
检查点是否在多边形内
290+
291+
~~~oraclesqlplus
292+
SELECT
293+
CASE
294+
WHEN SDO_INSIDE(
295+
SDO_GEOMETRY(2001, 8307, SDO_POINT_TYPE(120.3, 30.5, NULL), NULL, NULL),
296+
polygon_geom,
297+
0.01
298+
) = 'TRUE' THEN 'Inside'
299+
ELSE 'Outside'
300+
END AS position_status
301+
FROM administrative_areas
302+
WHERE area_id = 101;
303+
~~~
304+

0 commit comments

Comments
 (0)