0

我最近问了一个类似的问题,更适合 dplyr。

请参阅dplyr 和 monetdb - 查询 schema.table 的适当语法?

由于 dplyr 和 MonetDB(根据上面的@Hannes Mühleisen 回复)没有适当的方法来管理模式,我决定使用 MonetDB.R / DBI 本机函数。

同样在这种情况下,结果也存在一些问题:目前,MonetDB.R 似乎只能正确管理每个数据库的一个模式。

让我们看一些代码。我创建了两个模式,并在每个模式中创建了相同的表名(标准 sql 实践)。然后我尝试将数据写入每个。

> conn <– dbConnect(MonetDB.R(), "db.url", user= "monetdb", password="monetdb")
> df <- data.frame(i=10,j=20)
> q <- dbGetQuery(conn, "CREATE SCHEMA foo;")
> q <- dbGetQuery(conn, "SET SCHEMA foo;")
> q <- dbGetQuery(conn, "CREATE TABLE mytable (i int, j int);")
> q <- dbWriteTable(conn,  "mytable",df,overwrite=TRUE)
> q <- dbGetQuery(conn, "CREATE SCHEMA bar;")
> q <- dbGetQuery(conn, "SET SCHEMA bar;")
> q <- dbGetQuery(conn, "CREATE TABLE mytable (i int, j int);")

在这个阶段,我应该有两个名称相同但具有两个不同模式的表。dbListTables 证实了这一点(很高兴看到模式,但我可以没有它):

> dbListTables(conn)
[1] "mytable" "mytable"

但是,一旦我尝试使用与以前使用的查询相同的查询写入 mytable,灾难!

> q <- dbWriteTable(conn,  "mytable",df,overwrite=TRUE)
Error in .local(conn, statement, ...) : 
  Unable to execute statement 'INSERT INTO mytable VALUES (10, 20)'.
Server says 'INSERT INTO: no such table 'mytable'' [#42S02].

此时数据库处于混乱状态并要求回滚事务。

让我们尝试使用 overwrite=FALSE,看看是否有什么不同:

> df <- data.frame(i=10,j=20)
> q <- dbGetQuery(conn, "CREATE SCHEMA foo;")
> q <- dbGetQuery(conn, "SET SCHEMA foo;")
> q <- dbGetQuery(conn, "CREATE TABLE mytable (i int, j int);")
> q <- dbWriteTable(conn,  "mytable",df,overwrite=TRUE)
> q <- dbGetQuery(conn, "CREATE SCHEMA bar;")
> q <- dbGetQuery(conn, "SET SCHEMA bar;")
> q <- dbGetQuery(conn, "CREATE TABLE mytable (i int, j int);")
> dbListTables(conn)
[1] "mytable" "mytable"
> q <- dbWriteTable(conn,  "mytable",df,overwrite=FALSE)
Error in .local(conn, name, value, ...) : 
  Table mytable already exists. Set overwrite=TRUE if you want 
      to remove the existing table. Set append=TRUE if you would like to add the new data to the 
      existing table.

我击中了母矿脉append=true

> df <- data.frame(i=10,j=20)
> q <- dbGetQuery(conn, "CREATE SCHEMA foo;")
> q <- dbGetQuery(conn, "SET SCHEMA foo;")
> q <- dbGetQuery(conn, "CREATE TABLE mytable (i int, j int);")
> q <- dbWriteTable(conn,  "mytable",df,overwrite=TRUE)
> q <- dbGetQuery(conn, "CREATE SCHEMA bar;")
> q <- dbGetQuery(conn, "SET SCHEMA bar;")
> q <- dbGetQuery(conn, "CREATE TABLE mytable (i int, j int);")
> dbListTables(conn)
[1] "mytable" "mytable"
> q <- dbWriteTable(conn,  "mytable",df,append=TRUE)

后一个序列似乎可以正常工作并将数据加载到 bar 模式中而没有问题。但是你是否使用(像我通常那样)csvdump=TRUE你会得到另一个错误:

Error in .local(conn, statement, ...) : 
Unable to execute statement 'COPY 15 RECORDS INTO mytable FROM '/var/folders/m4/yfyjwcpj6rv5nq730bl9vr1h000...'.
Server says 'COPY INTO: no such table 'mytable'' [#42S02].

我总是可以避免使用csvdump,但我需要写大表......

我也尝试过copy_to& dplyr,但我也遇到了错误。

毫不奇怪,看到csvdump我也遇到了类似错误的问题monetdb.read.csv:如果在另一个模式中存在同名表时尝试加载 csv,则会出现错误。

难道我做错了什么?有没有更好的方法来做事?这是一个错误吗?

欢迎任何帮助。

4

1 回答 1

0

由于需要找到解决方案,我最终重写/重构了 MonetDB.R 中的所有主要标准函数。

作为一个简单的例子,这是替换的代码dbListTables

fdblisttables <- function(conn, schema){ 
  q <- dbGetQuery(conn, paste0("SELECT s.name AS name FROM sys.tables AS s
                               JOIN sys.schemas AS t ON s.schema_id=t.id WHERE t.name='", schema,"';" ))
  if(is.null(q$name)) q <- character() else q <- q$name    
}

公平地说,真正的问题是它DBI没有适合模式的语法(但如果有的话会很好......),所以MonetDB.R库开发人员的编程手有点束缚。

我意识到模式至少可以通过两种方式实现:

  • 隐含地,但它需要一种方法来从数据库中获取current schema当前不可用的monetdb(并且可能与其他数据库都不可用)
  • 显式地将关键字 schema 添加到函数调用中。最后,这就是我所做的,因为这是最简单的方法。另一方面,存在与现有代码等兼容性问题的风险。

像往常一样,欢迎任何建议和帮助。如果有兴趣,我会将我创建的函数发布在 github 的要点上。

于 2015-10-13T15:48:36.813 回答