将 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.latitude
和 location.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 数据库中的一堆位置的近似更改
没有互联网连接时如何将gps位置存储到android中的服务器
oracle 如何将字段类型varchar 改为blob 更改提示数据类型的变更无效