使用带有引用值的RSQLite加载数据

时间:2017-07-17 09:24:54

标签: r sqlite csv sqldf rsqlite

我正在尝试使用RSQLite包将一个大型的csv文件加载到SQL lite数据库中(我也尝试过sqldf包)。该文件包含所有英国邮政编码和各种查找值。

我想避免将其加载到R中并直接将其加载到数据库中。虽然这对于这项任务来说并不是绝对必要的,但我想这样做是为了让技术为不大的文件做好准备,如果我将来必须处理这些文件,那么这些文件将不适合。

不幸的是,csv提供了双引号中的值,dbWriteTable函数似乎无法剥离它们或以任何形式忽略它们。以下是文件的下载位置:http://ons.maps.arcgis.com/home/item.html?id=3548d835cff740de83b527429fe23ee0

这是我的代码:

# Load library
library("RSQLite")

# Create a temporary directory
tmpdir <- tempdir()

# Set the file name
file <- "data\\ONSPD_MAY_2017_UK.zip"

# Unzip the ONS Postcode Data file
unzip(file, exdir = tmpdir )

# Create a path pointing at the unzipped csv file
ONSPD_path <- paste0(tmpdir,"\\ONSPD_MAY_2017_UK.csv")

# Create a SQL Lite database connection
db_connection <- dbConnect(SQLite(), dbname="ons_lkp_db")

# Now load the data into our SQL lite database
dbWriteTable(conn = db_connection,
              name = "ONS_PD",
              value = ONSPD_path,
              row.names = FALSE,
              header = TRUE,
              overwrite = TRUE
              )

# Check the data upload
dbListTables(db_connection)
dbGetQuery(db_connection,"SELECT pcd, pcd2, pcds from ONS_PD  LIMIT 20")

遇到这个问题,我发现了一个参考教程(https://www.r-bloggers.com/r-and-sqlite-part-1/),建议使用sqldf包但不幸的是,当我尝试使用sqldf(read.csv.sql)中的相关函数时,我得到了相同的双引号问题。

在将csv文件导入sql系统时,这感觉就像是一个相当常见的问题,大多数导入工具都能够处理双引号,所以我很惊讶地遇到了这个问题(除非我错过了一个明显的帮助文件在这个问题的某个地方)。

编辑1

以下是我的csv文件中的一些示例数据,其形式为SQL表的输出输出:

structure(list(pcd = c("\"AB1 0AA\"", "\"AB1 0AB\"", "\"AB1 0AD\"", 
"\"AB1 0AE\"", "\"AB1 0AF\""), pcd2 = c("\"AB1  0AA\"", "\"AB1  0AB\"", 
"\"AB1  0AD\"", "\"AB1  0AE\"", "\"AB1  0AF\""), pcds = c("\"AB1 0AA\"", 
"\"AB1 0AB\"", "\"AB1 0AD\"", "\"AB1 0AE\"", "\"AB1 0AF\"")), .Names = c("pcd", 
"pcd2", "pcds"), class = "data.frame", row.names = c(NA, -5L))

编辑2

这是我尝试在sqldf的read.csv.sql函数中使用filter参数(请注意,Windows用户需要为此安装rtools)。不幸的是,这似乎仍然没有从我的数据中删除引号,尽管它神秘地删除了所有空格。

library("sqldf")
sqldf("attach 'ons_lkp_db' as new")
db_connection <- dbConnect(SQLite(), dbname="ons_lkp_db")
read.csv.sql(ONSPD_path,
              sql = "CREATE TABLE ONS_PD AS SELECT * FROM file",
              dbname = "ons_lkp_db",
              filter = 'tr.exe -d ^"'
              )

dbGetQuery(db_connection,"SELECT pcd, pcd2, pcds from ONS_PD  LIMIT 5")

另外,感谢那些认为这不是Stack Overflow(?!)范围内的编程问题的人的亲密投票。

3 个答案:

答案 0 :(得分:2)

RSQLite包中的CSV导入程序源自sqlite3 shell,导入CSV文件时,它本身似乎不支持引用的值(How to import load a .sql or .csv file into SQLite?doc) 。您可以使用readr::read_delim_chunked()

callback <- function(data) {
  name <- "ONS_PD"
  exists <- dbExistsTable(con, name)
  dbWriteTable(con, name, data, append = exists)
}

readr::read_delim_chunked(ONSPD_path, callback, ...)

用您的CSV文件所需的任何额外参数替换...

答案 1 :(得分:1)

使用带有read.csv.sql参数的sqldf包中的filter,并提供删除双引号或将其转换为空格的任何实用程序。

这个问题没有提供完全可重复的最小例子,但我在下面提供了一个。如果您使用read.csv.sql来挑选行或列的子集,那么只需添加相应的sql参数即可。

首先设置测试输入数据,然后尝试下面显示的任何一行解决方案。假设Windows,确保tr实用程序(在R的Rtools发行版中找到)或第三方csvfix实用程序(找到here,对于Linux也看到this)或trquote2space.vbs vbscript实用程序(请参阅结束)在你的道路上:

library(sqldf)
cat('a,b\n"1","2"\n', file = "tmp.csv")

# 1 - corrected from FAQ
read.csv.sql("tmp.csv", filter = "tr.exe -d '^\"'")

# 2 - similar but does not require Windows cmd quoting
read.csv.sql("tmp.csv", filter = "tr -d \\42")

# 3 - using csvfix utility (which must be installed first)
read.csv.sql("tmp.csv", filter = "csvfix echo -smq")

# 4 - using trquote2space.vbs utility as per Note at end
read.csv.sql("tmp.csv", filter = "cscript /nologo trquote2space.vbs")

任何一个给出:

  a b
1 1 2

您还可以使用任何其他合适的语言或实用程序。例如,虽然我怀疑tr和csvfix等专用工具运行得更快,但可以使用你的Powershell建议。

上述第一个解决方案已从常见问题解答中得到纠正。 (它在多年前撰写常见问题解答时确实有效,但现在在Windows 10中进行测试似乎需要指示的更改,或者可能是从最初找到的Google代码迁移到完全无法完成降价github使用略有不同的降价风格。)

对于Linux,tr本机可用,虽然引用与Windows不同,甚至可能依赖于shell。 csvfix也可以在Linux上使用,但必须安装。上面显示的csvfix示例在Windows和Linux上的工作方式相同。 vbscript显然特定于Windows。

注意: sqldf附带一个用vbscript编写的mini-tr实用程序。如果您将相关行更改为:

Dim sSearch  : sSearch  = chr(34)
Dim sReplace : sReplace = " "

并将名称更改为trquote2space.vbs,然后您将拥有一个Windows特定的实用程序来将双引号更改为空格。

答案 2 :(得分:0)

老实说,我找不到任何解决这个问题的方法。 sqldf文档说明 &#34;因此,.csv文件的一个限制是引号 在文件中不被视为特殊,因此数据字段中的逗号如 &#34;史密斯,詹姆斯&#34; 将被视为字段分隔符,引号将作为数据的一部分输入 可能不是预期的&#34;

所以,据我所知,似乎没有解决方案。

一种可能的次优方法(除了文本编辑器中明显的查找和替换) 是使用像这样的SQL命令

dbSendQuery(db_connection,"UPDATE ONS_PD SET pcd = REPLACE(pcd, '\"', '')")