【问题标题】:Bracket-escaped table names with dplyr带有 dplyr 的括号转义的表名
【发布时间】:2015-01-25 02:47:42
【问题描述】:

我正在以编程方式获取一堆数据集,其中许多具有以数字开头的愚蠢名称,并且其中包含特殊字符,例如减号。因为没有一个数据集特别大,而且我希望 R 对数据类型做出最好的猜测,所以我正在(ab)使用 dplyr 将这些表转储到 SQLite 中。

我使用方括号来转义可怕的表名,但这似乎不起作用。例如:

data(iris)
foo.db <- src_sqlite("foo.sqlite3", create = TRUE)
copy_to(foo.db, df=iris, name="[14m3-n4m3]")

这会导致错误消息:

Error in sqliteSendQuery(conn, statement, bind.data) : error in statement: no such table: 14m3-n4m3

如果我选择一个合理的名称,这将有效。但是,由于种种原因,我真的很想保留那些繁琐的名字。我也可以直接从 sqlite 创建这样一个名字不好的表:

sqlite> create table [14m3-n4m3](foo,bar,baz);
sqlite> .tables
14m3-n4m3

如果不深入研究,看起来 dplyr 正在以某种我无法理解的方式处理方括号。我怀疑这是一个错误,但我想先检查这里以确保我没有遗漏任何东西。

编辑:我忘了提到我只是将 janky 名称直接传递给 dplyr 的情况。这个错误如下:

library(dplyr)

data(iris)
foo.db <- src_sqlite("foo.sqlite3", create = TRUE)
copy_to(foo.db, df=iris, name="14M3-N4M3")

Error in sqliteSendQuery(conn, statement, bind.data) : 
  error in statement: unrecognized token: "14M3"

【问题讨论】:

  • 这只是一个猜测,但可能是因为 R 的命名约定。我发现的一种可能的解决方法是使用name=gsub("[.]", "", make.names("[14m3-n4m3]"))。如果您这样做了,您仍然可以在 copy_to() 中传递您的原始名称,尽管它们在数据中会略有不同。不确定这是否有帮助,但这是我的两分钱。很好的问题。
  • 这是一个比我开始实施的更好的解决方法。慢慢地让自己相信好名字 + 其他麻烦 > 坏名字。
  • dplyr 应该为您完成所有转义。如果你这样做copy_to(foo.db, df=iris, name="14m3-n4m3")会发生什么?
  • @hadley - 遗憾的是,这也不起作用。我已经为问题添加了更新;简短版本,我得到:unrecognized token: "14M3"我已经尝试过当前的 CRAN 版本以及install_github("hadley/dplyr")
  • 你能提交一个错误吗?这表明我忘记引用某些内容,或者我的引用不正确

标签: r sqlite dplyr


【解决方案1】:

这是 dplyr 中的一个错误。它仍然存在于当前的 github master 中。正如@hadley 所指出的,他试图在 dplyr 中转义诸如表名之类的内容以防止此问题。您当前遇到的问题源于两个函数中缺少转义。当提供未转义的表名时(并使用dplyr::db_create_table 完成),表创建工作正常。但是,向表中插入数据是使用不支持奇数表名的DBI::dbWriteTable 完成的。如果提供给此函数的表名已转义,则它无法在表列表中找到它(您报告的第一个错误)。如果提供了转义,则执行插入的 SQL 在语法上无效。

第二个问题出现在表格更新时。获取字段名称的代码,这次实际上是在 dplyr 中,再次无法转义表名称,因为它使用 paste0 而不是 build_sql

我已在a fork of dplyr 修复了这两个错误。我还向@hadley 提出了拉取请求,并就问题https://github.com/hadley/dplyr/issues/926 做了注释。同时,如果您愿意,可以使用devtools::install_github("NikNakk/dplyr", ref = "sqlite-escape"),然后在修复后恢复到主版本。

顺便说一句,在 SQL 中转义表名(和其他标识符)的正确 SQL-99 方法是使用双引号(请参阅SQL standard to escape column names?)。 MS Access 使用方括号,而 MySQL 默认使用反引号。 dplyr 根据标准使用双引号。

最后,@RichardScriven 的提议不会普遍适用。例如,select 在 R 中是一个完全有效的名称,但在 SQL 中不是语法上有效的表名。其他保留字也是如此。

【讨论】:

  • 为一个长期存在的错误发布 PR 来回答这个问题——太棒了!
  • 如果你很快下载了我的固定版本,我已经做了另一个提交,它添加了一行额外的代码来在插入后清理资源。不确定这有多重要,但这样做似乎很明智,并且在原始 DBI::dbWriteTable 中。
  • 在与@hadley 讨论后,我的解决方案现在是一个更简单的解决方案,可以解决上述第二个问题(将paste0 替换为build_sql)。对DBI::dbWriteTable 的必要更改已在RSQLite in the github version 中进行,但您还需要github version of DBI
猜你喜欢
  • 1970-01-01
  • 2019-01-11
  • 1970-01-01
  • 2020-11-30
  • 1970-01-01
  • 2019-11-03
  • 2021-10-14
  • 2017-07-11
相关资源
最近更新 更多