2012-08-14 25 views
9

Mi tabla de base de datos se ve aproximadamente así:RODBC: SQLUpdate() no reconoce columna de índice

+-----+-------+--------------------+-----------+----------+ 
| 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 | 
+-----+-------+--------------------+-----------+----------+ 

La primera columna (ID1) se define como PK. Sin embargo, ID2 también es único.

Ahora me gustaría poder cambiar FilePath2 y Status con R usando sqlUpdate() del paquete RODBC. Así que trato de los siguientes:

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) 

que db.df es una trama de datos con los nombres de una sola fila y columna correspondientes a los de la tabla de base de datos (sin embargo, les dejo algunas de las columnas, en este caso FilePath1, y yo También preferiría omitir ID1, si es posible). Mi objetivo es conseguir la siguiente:

+-----+-------+--------------------+--------------------+----------+ 
| 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 | 
+-----+-------+--------------------+--------------------+----------+ 

consigo el error siguientes iniciales:

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

Cuál podría ser la razón para este problema?


EDIT: He pasa por alto el problema mediante el envío de una consulta SQL directa:

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) 

Aunque esto podría no ser una forma elegante, que hace lo que debe hacer. Sin embargo, todavía no entiendo cuál es el problema con sqlUpdate, así que espero que alguien pueda aclararlo.

Respuesta

0

El sqlUpdate funcionó para mí. lo único que tuve que cambiar fue db.df - necesario para duplicar el carácter \ para que no intentara escapar el código con él. Mi tabla de prueba era la siguiente:

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') 

que era capaz de ejecutar la actualización sin los campos ID1 o FilePath1 en la actualización. Si lee la documentación (? SqlUpdate) indica: 'Primero busca una clave primaria para la tabla, luego para la (s) columna (s) que la base de datos considera como la óptima para definir una fila únicamente' No tiene que usar la clave principal, aunque si no sabía que ID2 era único, lo mejor sería usar esa clave primaria.

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

que experimentaron un problema similar cuando se utiliza sqlUpdate actualizar una tabla en MySQL. Lo arreglé estableciendo los atributos case en la conexión R-MySQL.

Ahí está el detalle:

En 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') 

En 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 

La razón es que el (por defecto?) Atribuye en relación RMySQL tiene:

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

Así, nomCol myName1 en myDF caso se cambia a myname1 dentro sqlUpdate, por lo que no coincide con myName1 índice dado.

Tenga en cuenta que no funcionará si cambia la llamada con index = 'myname1'. Se informará un error de index column(s) myName1 not in database table. Porque en la tabla MySQL, el colname es myName.

La solución es establecer el caso atribuye a 'nochange' cuando o después de la conexión:

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

Aquí hay más detalles:

debugonce(sqlUpdate) da:

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 
    } 

Nota del intable llama a cname y coldata.

0

En algunos casos, especialmente si está pasando varias columnas, debe especificar la estructura de la columna explícitamente como nombres de columna.

Ejemplo: SQLUpdate (MyConn, db.df, nombredetabla = '' mitabla, índice de nombres = ('ID2'), verbosa = VERDADERO)

Actualización: Por lo que parece a veces sigue fallando. El nuevo trabajo que utilicé es:

Esto le permite pasar una lista de columnas si es necesario. No sé por qué estaba siendo quisquilloso a la inversa.

indexNames < -list ("ID2")

SQLUpdate (MyConn, db.df, nombretabla = 'mitabla', índice = as.character ("ID2"), verbose = TRUE)