RODBC:sqlUpdate()无法识别索引列

时间:2012-08-14 08:42:21

标签: sql r rodbc

我的数据库表看起来大致如下:

+-----+-------+--------------------+-----------+----------+
| ID1 | ID2   | FilePath1          | FilePath2 | Status   |
+-----+-------+--------------------+-----------+----------+
| 1   | Test1 | MyFolder\R\Folder1 | NULL      | Open     |
| 2   | Test2 | MyFolder\R\Folder2 | NULL      | Open     |
| 3   | Test3 | MyFolder\R\Folder3 | NULL      | Finished |
| 4   | Test4 | MyFolder\R\Folder4 | NULL      | Finished |
+-----+-------+--------------------+-----------+----------+

第一列(ID1)定义为PK。但是,ID2也是独一无二的。

现在,我希望能够使用来自FilePath2包的Status来更改sqlUpdate()RODBC。所以我尝试以下方法:

db.df <- data.frame(ID1=1, ID2='Test1',
                    FilePath2='MyFolder\R\Folder5', Status='Finished',
                    stringsAsFactors=FALSE)

sqlUpdate(myconn, db.df, tablename='mytable', index='ID2', verbose=TRUE)

其中db.df是一个数据框,其中一个行名和列名对应于数据库表中的那些(但是,我省略了一些列,在本例中为FilePath1,而且我是如果可能的话,也更愿意遗漏ID1。我的目标是获得以下内容:

+-----+-------+--------------------+--------------------+----------+
| ID1 | ID2   | FilePath1          | FilePath2          | Status   |
+-----+-------+--------------------+--------------------+----------+
| 1   | Test1 | MyFolder\R\Folder1 | MyFolder\R\Folder5 | Finished |
| 2   | Test2 | MyFolder\R\Folder2 | NULL               | Open     |
| 3   | Test3 | MyFolder\R\Folder3 | NULL               | Finished |
| 4   | Test4 | MyFolder\R\Folder4 | NULL               | Finished |
+-----+-------+--------------------+--------------------+----------+

我得到了以下错误:

Error in sqlUpdate(myconn, db.df, tablename = 'mytable', index = 'ID2',  : 
index column(s) ID2 not in database table

这个问题可能是什么原因?


编辑:我通过发送直接SQL查询绕过了问题:

out.path <- 'MyFolder\\\\R\\\\Folder5'
update.query <- paste("UPDATE mytable ", 
                  "SET FilePath2='", out.path, "', Status='Finished' ",
                  "WHERE ID2='Test1'", sep="")
dummy <- sqlQuery(myconn, update.query)

虽然这可能不是一种简洁的方式,但它可以做它应该做的事情。但是,我仍然不明白sqlUpdate的问题是什么,所以我希望有人能够阐明它。

3 个答案:

答案 0 :(得分:1)

使用sqlUpdate更新MySQL中的表时遇到了类似的问题。我通过在R-MySQL连接中设置case属性来修复它。

以下是详细信息:

在MySQL中:

create table myTable (
myName1 INT NOT NULL PRIMARY KEY,
myName2 VARCHAR(10) NOT NULL,
);

insert into myTable values(111, 'Test1')
insert into myTable values(222, 'Test2')

在R:

myDF <- data.frame(myName1 = 111, myName2 = 'Test3')
sqlUpdate(myConn, myDF, tablename='myTable', index = 'myName1', verbose=TRUE)

#> Error in sqlUpdate(myConn, myDF, tablename='myTable', index = 'myName1', verbose=TRUE) : 
  index column(s) myName1 not in data frame

原因是RMySQL连接中的(默认?)属性具有:

> attr(myConn, "case")
[1] "tolower"

因此,myDF中的colname myName1myname1内更改为sqlUpdate,因此它与给定索引的myName1不匹配。

请注意,如果使用index = 'myname1'更改通话,则无效。将报告index column(s) myName1 not in database table的错误。因为在MySQL表中,colname是myName。

解决方案是在连接时或之后将案例属性设置为'nochange':

attr(myConn, "case") <- 'nochange'

以下是更多详情:

debugonce(sqlUpdate)给出:

   cnames <- colnames(dat)
    cnames <- mangleColNames(cnames)
    cnames <- switch(attr(channel, "case"), nochange = cnames, 
        toupper = toupper(cnames), tolower = tolower(cnames))
    cdata <- sqlColumns(channel, tablename)
    coldata <- cdata[c(4L, 5L, 7L, 9L)]
    if (is.character(index)) {
        intable <- index %in% coldata[, 1L]
        if (any(!intable)) 
            stop("index column(s) ", paste(index[!intable], collapse = " "), 
                " not in database table")
        intable <- index %in% cnames
        if (any(!intable)) 
            stop("index column(s) ", paste(index[!intable], collapse = " "), 
                " not in data frame")
        indexcols <- index
    }

请注意intablecname的{​​{1}}来电。

答案 1 :(得分:0)

sqlUpdate为我工作。我唯一需要更改的是db.df - 需要加倍\字符,以便它不会尝试使用它来转义代码。我的测试表看起来像这样:

CREATE TABLE mytable  (
    ID1 INT NOT NULL PRIMARY KEY,
    ID2 VARCHAR(10) NOT NULL,
    FilePath1 VARCHAR(50) NOT NULL,
    FilePath2 VARCHAR(50) NULL,
    Status VARCHAR(15) NOT NULL)

insert into mytable values(1,'Test1','MyFolder\R\Folder1',NULL,'Open')
insert into mytable values(2,'Test2','MyFolder\R\Folder2',NULL,'Open')
insert into mytable values(3,'Test3','MyFolder\R\Folder3',NULL,'Finished')
insert into mytable values(4,'Test4','MyFolder\R\Folder4',NULL,'Finished')

我能够在更新中运行没有ID1或FilePath1字段的更新。如果您阅读文档(?sqlUpdate),它会声明:'首先它查找表的主键,然后查找数据库视为唯一定义行唯一的列 “ 因此您不必使用主键,但如果您不知道ID2是唯一的,那么最好使用该主键。

db.df <- data.frame(ID2='Test1', FilePath2='MyFolder\\R\\Folder5', Status='Finished',                    stringsAsFactors=FALSE)
sqlUpdate(myconn, db.df, tablename='mytable', index='ID2', verbose=TRUE)

答案 2 :(得分:0)

在某些情况下,特别是如果要传递多个列,则需要将列结构明确指定为列名。

示例:sqlUpdate(myconn,db.df,tablename =&#39; mytable&#39;,index = names(&#39; ID2&#39;),verbose = TRUE)

更新:所以有时它似乎仍然失败。我使用的新工作是:

这允许您根据需要传递列表。不知道为什么它反其道而行。

indexNames&LT; -list(&#34; ID2&#34)

sqlUpdate(myconn,db.df,tablename =&#39; mytable&#39;,index = as.character(&#34; ID2&#34;),verbose = TRUE)