将 GPS 位置存储在数据库 varchar 字段中

Posted

技术标签:

【中文标题】将 GPS 位置存储在数据库 varchar 字段中【英文标题】:Storing GPS locations in a database varchar field 【发布时间】:2009-03-05 10:15:55 【问题描述】:

如果有人提出任何建议,我将不胜感激:

您如何有效地将 gps(或任何浮点数)存储在可索引的 varchar 字段中。


背景:

我们开发了一个内容管理系统,可以有效地将任何类型的文件与元数据集合一起存储。该文件/元数据存储如下:

file_table              metadata_table
----------              --------------
file_id         ->      file_id (number)
file_name               metadata_id (number)
file_location           metadata_value (varchar)
...etc

我被要求为地理标记文件提供支持(即,将 gps 坐标存储为元数据)。此外,我们还希望支持具有多个地理标签的文件。

现在据我所知,我有几个选择:

1) 将纬度和经度存储在同一个 metadata_value varchar 中(例如,'52.4343242,-1.32324')。

我将如何查询这个字符串?我可以用 sql 做些什么聪明的事情来让我查询字符串的“组件”?我可以将坐标存储为 xml 字符串吗?这有帮助吗?如何有效地对其进行索引?

2) 将纬度和经度作为单独的行存储在 metadata_table 中。

此解决方案解决了支持更轻松查询的问题(以复杂性和笨拙为代价,特别是当我将在每个文件中存储多个地理标签时),但是我仍然面临索引问题。

我可以在查询时将 varchars 转换为浮点数,但我不确定这是否会忽略我在 metadata_table.metadata_value 上的索引并改为执行表扫描。

3) 创建专用浮点字段来存储 GPS 数据。

这是最不可取的选项,因为它违背了为特定元数据添加数据库字段的设计原则。并非所有文件都会存储 GPS 数据。

任何帮助或建议表示赞赏。

【问题讨论】:

【参考方案1】:

您可以使用 Oracle 定位器。 Oracle Spatial 的免费子集,用于对空间数据进行各种不同的地理操作和索引:http://www.oracle.com/technology/products/spatial/index.html

通过使用列类型 mdsys.sdo_geometry,您可以在数据库中存储点、点云、线、多边形和 3D 事物。

【讨论】:

【参考方案2】:

这有什么帮助吗:http://postgis.refractions.net

【讨论】:

【参考方案3】:

虽然您已使用 Oracle 标记了此内容,但我认为这对使用 mysql 的任何人都有用:use the spatial extensions to store location data。

【讨论】:

【参考方案4】:

使用 mdsys.sdo_geometry 类型的专用浮点字段或列是存储此数据的最佳方式。如果文件没有 GPS 数据,这些字段将为空,但为什么会出现问题?如果一个文件可以关联多个点,请使用详细信息表。

选项 1 和 2 是“通用”解决方案。通用数据库解决方案很慢,因为它们更难以索引并且收集统计数据变得更加困难,因此查询优化器的生活变得更加困难。

此外,使用 Cognos(商业智能)等工具在通用解决方案上收集管理信息的报告对您的用户来说更难。

在日期字段中存储日期,在数字字段中存储数字,在地理字段中存储地理信息 (mdsys.sdo_geometry)。

这里解释了为什么在数字字段中存储像“20031603”这样的日期会减慢速度:http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:77598210939534。

【讨论】:

【参考方案5】:

对于选项 1,我可以说:使用 Gps eXchange Format (GPX)。这是保存 GPS 点的标准方法。有标记航点、轨迹和兴趣点的选项。 但是,查询起来并不容易。

【讨论】:

【参考方案6】:

一般来说,如果我有一个千篇一律的表(我并不是说它们没有用),我倾向于允许存储一系列数据类型,并在类型之前进行。例如

CREATE TABLE MetaDataType (
  MetaDataID int IDENTITY(1,1) not null,
  MetaDataType varchar(10) not null,
  constraint PK_MetaDataType PRIMARY KEY (MetaDataID),
  constraint UQ_MetaDataType_TypeCheck UNIQUE (MetaDataID,MetaDataType),
  constraint CK_MetaDataType CHECK (MetaDataType in ('INT','CHAR','FLOAT'))
)

然后元数据表将如下所示:

CREATE TABLE MetaData (
  FileID int not null,
  MetaDataID int not null,
  MetaDataType varchar(10) not null,
  IntValue int null,
  CharValue varchar(max) null,
  FloatValue float null,
  constraint PK_MetaData PRIMARY KEY (FileID,MetaDataID),
  constraint FK_MetaData_Files FORIEGN KEY (FileID) references /* File table */,
  constraint FK_MetaData_Types FOREIGN KEY (MetaDataID,MetaDataType) references MetaDataTypes (MetaDataID,MetaDataType),
  constraint CK_MetaData_ValidTypes ((MetaDataType = 'INT' or IntValue is null) and (MetaDataType = 'CHAR' or CharValue is null) and (MetaDataType = 'FLOAT' or FloatValue is null))
)

重点在于 1) 您为每个元数据项存储预期的类型,以及 2) 您在元数据表中强制执行。

【讨论】:

忘了说,上面的设计允许存储空值。如果您想防止这种情况发生,请添加一个额外的 CHECK 约束以确保至少有一个 *Value 列不为空【参考方案7】:

编辑:查看 cmets 了解不足之处。

要回答您的基本问题,忽略其背后的任何原因,您可以使用function-based indexes。如果您选择选项#2,这应该是直截了当的。

如果你坚持使用#1,你只需要添加一些 instr/substr voodoo;例如:

select 
    to_number(
      substr(
          '52.4343242,-1.32324'
        , 1
        , instr( '52.4343242,-1.32324', ',' ) - 1
      )
    ) as lattitude
  , to_number(
      substr(
          '52.4343242,-1.32324'
        , instr( '52.4343242,-1.32324', ',' ) + 1
      )
    ) as longitude
from dual;

所以你会做这样的事情:

create index lat_long_idx on metadata_table ( 
    to_number(
      substr(
          metadata_value
        , 1
        , instr( metadata_value, ',' ) - 1
      )
    )
  , to_number(
      substr(
          metadata_value
        , instr( metadata_value, ',' ) + 1
      )
    )
);

【讨论】:

to_number(instr... 当 metadata_value 中没有存储纬度和经度时会产生错误。请记住,此字段以通用方式使用,因此它也应该能够存储不同的数据。我认为一般存储时几乎不可能索引纬度和经度。 好点。这也可能意味着只做索引的 substr 部分也是无效的。也许创建一个仅包含纬度/经度数据和索引的物化视图是一种选择。【参考方案8】:
    只需将纬度和经度分配给一个变量,如下所示,并将此变量作为字符串 (varchar) 存储到数据库中。

例子:

location = position.coords.latitude + "," + position.coords.longitude;
    在通过此location 变量获取位置时,请执行以下操作。

例子:

$location = explode(',',$fatched_row['location']); //in php
OR
in javascript use Split() Function.

你会得到location.latitude & location.longitude

在您的地图中使用此 location.latitudelocation.longitude

NOTE: location.latitude & location.longitude variable have string type,change it into number.

Example:
Number(location.latitude);
Number(location.longitude);
google.maps.LatLng($latitude,$longitude);

【讨论】:

以上是关于将 GPS 位置存储在数据库 varchar 字段中的主要内容,如果未能解决你的问题,请参考以下文章

gps 对存储在 sqlite 数据库中的一堆位置的近似更改

Python - 将 GPS 位置批量转换为经纬度小数

没有互联网连接时如何将gps位置存储到android中的服务器

oracle 如何将字段类型varchar 改为blob 更改提示数据类型的变更无效

数据库中存储日期的字段类型到底应该用varchar还是datetime

使用nodejs和数据库存储GPS纬度和经度的最佳方法