我们需要将数据库表与 Excel 文件的内容连接起来。使用 a 很简单dplyr
left_join
,但需要copy=TRUE
在连接中设置它,因为数据不是来自同一源。这又意味着只有当数据库用户具有 INSERT 权限时代码才会运行,以便left_join
可以在 /tmp 文件夹中创建临时表。
有没有办法copy=TRUE
left_join
在不授予 INSERT 权限的情况下执行此操作?访问数据进行分析的数据库用户实际上应该只是读者。
如果未授予插入权限,则会出现如下错误:
Error in .local(conn, statement, ...) :
could not run statement: INSERT command denied to user
'reader'@'192.168.135.1' for table 'utiexriryc'
Run Code Online (Sandbox Code Playgroud)
将出现(每次连接时都有不同的随机表名称)。
一个简短的可重现示例很困难,因为它需要一个数据库连接(在本例中为 mysql wtih src_mysql()
)和一个 excel 文件(在本例中为 读取readxl
)。连接看起来像:
df.biozones <- db.sites %>%
left_join(ef.join_site_ids, by=c("site_id"="id"), copy=TRUE) %>%
collect()
Run Code Online (Sandbox Code Playgroud)
其中 db.sites 是一个 mysql 数据库表,ef.join_site_ids 是一个使用 readxl 读取的 Excel 电子表格中的 data.frame。
有没有办法在 dplyr 中执行上述操作并避免为读取数据的用户授予 INSERT 权限?
虽然没有办法直接按照我的要求做,正如@hadley所说,但有不同的方式来看待这个问题。我花了一些时间才理解 dplyr 将每个连接视为差异源(或src
简称)。src
内存中的对象集合始终存在。
所以在我的问题中,我实际上正在处理三个来源:
这三者之间的任何连接都需要 dplyr 的权限来创建临时表并将其插入其中。这三者中任何一个的任何加入都不会成为问题。因此,当您无法获得数据库的附加权限时,有(至少)三种可能的方法来处理此问题。
1.将所有内容加载到内存中
如果您将两个数据库中所需的所有对象放入内存中,那么您将把它们放入共享数据库中src
,并且能够对它们进行任何连接。Dplyr 提供了collect()
执行此操作的函数:
db_table_of_interest <- tbl(Database_1, "table_of_interest")
df_table_of_interest <- collect(db_table_of_interest).
Run Code Online (Sandbox Code Playgroud)
事实上,您将把表变成本地数据框。您需要对所有感兴趣的数据库中的所有感兴趣的表执行此操作。只要您有足够的 RAM 来保存您正在读取的所有数据,它就可以正常工作。
2. 在数据库之间复制标识符
如果(就像我们的情况)您需要在两个数据库之间连接记录标识符(例如站点或样本 ID),而这两个数据库在不同 ID 下具有相同站点,那么最简单的方法是将两个数据库中的表中的 ID 加倍。因此,不要使用外部表来列出每个数据库中每个站点的所有 ID 并设置匹配项,而是在每个数据库的 site_table 中添加一列并引用另一列。
只要您不需要使用实际数据设置连接表,那么就可以了。例如,如果您需要读取按物种分类的站点和按环境分类的站点表,其中物种和环境数据存储在单独的数据库中,并且每个站点都有不同的 ID。
如果您确实需要连接表,那么至少您可以在执行collect()
并读取内存中的所有内容之前在两个数据库中进行预选择。当有大量数据需要读取时,这将节省您的内存需求。
3. 将所有内容复制到一个分析数据库中
如果由于某种原因无法使用更多内存,那么理论上您可以首先将所有数据复制到一个数据库中。我无法想象这在任何情况下都是可行的选择,除非只有几个感兴趣的表,以便将它们合并到一个新的联合数据库中是可行的。也许在数据集非常大并且不会改变的情况下。
如果我在此列表中遗漏了某个选项,我很高兴知道您可能找到了哪些其他解决方案。