【发布时间】:2020-12-13 19:22:10
【问题描述】:
使用R 中的sf 对象,以及MariaDB 中带有geometry(在本例中为point)列的表,我正在努力在两者之间有效地移动数据(@987654326 @对象到MariaDB表,反之亦然)。
请注意,我使用RMariaDB 包连接到MariaDB,并在此处将我的连接定义为consdb。
示例数据:
library(sf)
pnt <- data.frame( name = c("first", "second"),
lon = c(145, 146),
lat = c(-38, -39) )
pnt <- st_as_sf( pnt, coords = c("lon", "lat") )
尝试直接写sf对象
理想情况下,我希望能够使用dbWriteTable 或dbAppendTable 将这样的sf 对象直接写入MariaDB。目前,这会出现兼容性错误。
如果我尝试使用dbWriteTable:
dbWriteTable(consdb, "temp", pnt, temporary=TRUE, overwrite=TRUE)
# Error in result_bind(res@ptr, params) : Cannot get geometry object from data you send to the GEOMETRY field [1416]
或者先创建表:
dbExecute(consdb, "CREATE OR REPLACE TEMPORARY TABLE temp (name VARCHAR(10), geometry POINT)")
dbAppendTable(consdb, "temp", pnt)
# Error in result_bind(res@ptr, params) : Unsupported column type list
尝试在插入时转换为点类型
如果我使用 SQL 插入查询进行插入,我会像这样使用 PointFromText
INSERT INTO temp (name, geometry) VALUES ('new point', PointFromText('POINT(145 38)', 4326));
所以我尝试使用它来将数据作为字符串发送。我编写了几个函数来将 sf 几何列转换为适当的字符串列:
# to convert 1 value
point_to_text <- function(x, srid = 4326) {
sprintf("PointFromText('POINT(%f %f)', %i)", x[1], x[2], srid)
}
# to apply the above over a whole column
points_to_text <- function(x, srid = 4326) {
vapply(x, point_to_text, srid = srid, NA_character_)
}
用它把sf对象变成data.frame
for_sql <- data.frame(pnt)
for_sql$geometry <- points_to_text(for_sql$geometry)
几何列现在是一个字符列,例如:PointFromText('POINT(145.000000 -38.000000)', 4326)
使用dbWriteTable 只会创建一个文本列,所以我尝试创建表格,然后使用dbAppendTable:
dbExecute(consdb, "CREATE OR REPLACE TEMPORARY TABLE temp (name VARCHAR(10), geometry POINT)")
dbAppendTable(consdb, "temp", pnt)
# Error in result_bind(res@ptr, params) : Cannot get geometry object from data you send to the GEOMETRY field [1416]
可行,但看起来很傻
如果我创建一个临时 SQL 表,将列更改为文本,从 R 中插入数据,在 SQL 中转换列,然后将其附加到原始 SQL 表,我可以让它工作。它看起来非常复杂,但只是为了表明它有效:
# create temporary table
dbExecute(consdb, "CREATE OR REPLACE TEMPORARY TABLE temp_geom LIKE temp")
# change the geometry column to text
dbExecute(consdb, "ALTER TABLE temp_geom MODIFY COLUMN geometry TEXT")
# add the data to the temporary table
dbAppendTable(consdb, "temp_geom", for_sql)
# add a new point column
dbExecute(consdb, "ALTER TABLE temp_geom ADD COLUMN geom_conv POINT")
# convert strings to points
dbExecute(consdb, "UPDATE temp_geom SET geom_conv = PointFromText(geometry, 4326)")
# drop the old column and replace it with the new one
dbExecute(consdb, "ALTER TABLE temp_geom DROP COLUMN geometry")
dbExecute(consdb, "ALTER TABLE temp_geom CHANGE COLUMN geom_conv geometry POINT")
# append the data from the temporary table to the main one
dbExecute(consdb, "INSERT INTO temp SELECT * FROM temp_geom")
是否有其他人为此使用的任何解决方案,或者任何可能解决在sf 对象和MariaDB 表之间传递数据的问题?
编辑添加:根据@SymbolixAU 的评论,我现在尝试了以下方法
st_write(
obj=pnt, # the sf class object, as created above
dsn=consdb, # the MariaDB connection
layer="temp", # the table name on MariaDB
append=TRUE,
layer_options=c('OVERWRITE=false', 'APPEND=true')
)
# Error in result_bind(res@ptr, params) :
Cannot get geometry object from data you send to the GEOMETRY field [1416]
【问题讨论】:
-
你试过直接
sf::st_write()吗?例如,当我写信给 Postgres 时,这对我有用:sf::st_write( obj = sf, dsn = consdb, layer = tbl, append = TRUE, layer_options = c('OVERWRITE=false', 'APPEND=true' ) ) -
感谢@SymbolixAU 的提示,我只是尝试了一下,但没有成功。我将编辑帖子以添加它作为尝试。
-
您的坐标应该按“lon”、“lat”而不是“lat”、“lon”的顺序排列吗? (你的纬度是 145,我认为是 miatake)
-
好地方@SymbolixAU 是的,这是一个错误。不幸的是,它不能解决问题。有趣的是,我可以让
st_write编写一个新表(而不是追加),但几何值会转换为奇怪的值。在这种情况下,例如:“010100000000000000000043c00000000000206240” -
这是众所周知的二进制,它是几何的二进制表示。这是存储数据的标准方式。