在Oracle中:我有一个表空间,其中记录了许多汽车的位置.每条记录都有里程、时间、经度和纬度.表空间有五列:‘PLATENO’、‘SENDTIME’、‘Mileage’和‘LATIMATION’.它们分别代表汽车的车牌号、位置、发送时间、里程和汽车的两个坐标.‘SENDTIME’列中的值采用DATETIME格式.还有,我有一些建筑物的坐标.我要找出轨迹在大楼附近200米的车辆.因此,我创建了一个名为Builds的表来记录建筑物,如下所示:

CREATE TABLE BUILDINGS (
  NAME VARCHAR2(50) NOT NULL,
  ADDR VARCHAR2(50) NOT NULL,
  LONGITUDE NUMBER NOT NULL,
  LATITUDE NUMBER NOT NULL
);


INSERT INTO BUILDINGS (NAME, ADDR, LONGITUDE, LATITUDE) VALUES (
                      '北京市大兴区永兴路7号院1号楼1F2F局部内装修工程', '北京市大兴区永兴路7号院1号楼',
                      116.314497, 39.685536);
INSERT INTO BUILDINGS (NAME, ADDR, LONGITUDE, LATITUDE) VALUES (
                      '北京金沃夫生物工程科技有限公司23号楼诊断试剂GMP生产车间及配套实验室、研发实验室建设项目', '北京市大兴区华佗路50号院',
                      116.282965, 39.668402);

然后使用sdo_geom.sdo_Distance函数计算距离,找到满足我要求的线段.

select g.PLATENO, g.SENDTIME, g.MILEAGE, g.LONGITUDE, g.LATITUDE, 
b.NAME as BUILDING_NAME, b.ADDR, b. LONGITUDE, b.LATITUDE
from GPSINFO g, BUILDINGS b
where sdo_geom.sdo_distance (
  sdo_geometry (2001, 4326, sdo_point_type (g.LONGITUDE, g.LATITUDE, null), null, null),
  sdo_geometry (2001, 4326, sdo_point_type (b.LONGITUDE, b.LATITUDE, null), null, null),
  0.01,
  'unit=M'
) <= 200;

但是查询运行得相当慢.我只需要三条符合我标准的记录.如何优化我的代码?我先试着取,但不起作用:

select v.PLATENO, v.SENDTIME, v.MILEAGE, v.LONGITUDE, v.LATITUDE, b.NAME as BUILDING_NAME
from VEHICLES v, BUILDINGS b
where sdo_geom.sdo_distance (
  sdo_geometry (2001, 4326, sdo_point_type (v.LONGITUDE, v.LATITUDE, null), null, null),
  sdo_geometry (2001, 4326, sdo_point_type (b.LONGITUDE, b.LATITUDE, null), null, null),
  0.01,
  'unit=M'
) <= 50
and HAVERSINE(v.LONGITUDE, v.LATITUDE, b.LONGITUDE, b.LATITUDE) <= 50
ORDER BY v.SENDTIME DESC
FETCH FIRST 3 ROWS ONLY;

推荐答案

无需将longitudelatitude存储为NUMBER数据类型,然后在查询中转换为SDO_GEOMETRY,您可以将它们存储为SDO_GEOMETRY类型并添加空间索引:

CREATE TABLE BUILDINGS (
  NAME      VARCHAR2(200) NOT NULL,
  ADDR      VARCHAR2(200) NOT NULL,
  LOCATION  SDO_GEOMETRY NOT NULL
);

INSERT INTO USER_SDO_GEOM_METADATA (
  TABLE_NAME, COLUMN_NAME, DIMINFO, SRID
) VALUES (
  'BUILDINGS',
  'LOCATION', 
  SDO_DIM_ARRAY(
    SDO_DIM_ELEMENT('LONG', -180.0, 180.0, 0.0001), 
    SDO_DIM_ELEMENT('LAT', -90.0, 90.0, 0.0001)
  ), 
  4326
);

CREATE INDEX Buildings_SIDX ON Buildings( location ) INDEXTYPE IS MDSYS.SPATIAL_INDEX;

然后,您可以插入数据:

INSERT INTO BUILDINGS (NAME, ADDR, LOCATION)
VALUES (
  '北京市大兴区永兴路7号院1号楼1F2F局部内装修工程',
  '北京市大兴区永兴路7号院1号楼',
  sdo_geometry(2001, 4326, sdo_point_type (116.314497, 39.685536, null), null, null)
);

INSERT INTO BUILDINGS (NAME, ADDR, LOCATION)
VALUES (
  '北京金沃夫生物工程科技有限公司23号楼诊断试剂GMP生产车间及配套实验室、研发实验室建设项目',
  '北京市大兴区华佗路50号院',
  sdo_geometry(2001, 4326, sdo_point_type (116.282965, 39.668402, null), null, null)
);

如果您想要获取位置的组件,则可以使用嵌套对象(注意:您需要确保从表别名开始):

SELECT b.name,
       b.addr,
       b.location.sdo_point.x AS longitude,
       b.location.sdo_point.y AS latitude
FROM   buildings b

以下哪项输出:

NAME ADDR LONGITUDE LATITUDE
北京市大兴区永兴路7号院1号楼1F2F局部内装修工程 北京市大兴区永兴路7号院1号楼 116.314497 39.685536
北京金沃夫生物工程科技有限公司23号楼诊断试剂GMP生产车间及配套实验室、研发实验室建设项目 北京市大兴区华佗路50号院 116.282965 39.668402

您可以对GPSINFO表进行相同的更改,然后您的查询将不需要在运行时生成大量对象,并且您可以利用索引.

您也不需要同时使用空间比较和HAVERSINE函数.

fiddle

Sql相关问答推荐

SQL:创建查询以添加减少的总数

JSON列之间的Postgr聚合

SQL是否可以计算每年的所有日期变化?

用于匹配红旗和绿旗的SQL查询

过go 四周未填充的数据,即W50,51,52-SQL

带上最后日期(结果)

了解多个分组集

提取连续时间戳范围的SQL

使用递归CTE在BigQuery中获取文件路径

显示所有组并计算给定组中的项目(包括 0 个结果)

DB2 SQL查询结果多余数据

通过ID和数据找到每个不同的值

如何为给定的股票数据集计算利润/亏损,确保先卖出先买入的股票

如何创建一个递归计数器来查找一个元素有多少父级和子级?

Snowflake中的动态SQL优化

获取 SQL Server 中每一行的两个-之间的文本

将有效数字作为 varchar 返回的 SQL 函数

雅典娜弄错了操作顺序

如何找到特定时间间隔内的最大和最小日期?

Lag() 获取snowflake的值变化