2012-08-14 16 views
9

La mia tabella di database si presenta circa così:RODBC: SQLUpdate() non riconosce colonna indice

+-----+-------+--------------------+-----------+----------+ 
| 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 prima colonna (ID1) è definita come PK. Tuttavia, ID2 è anche unico.

Ora mi piacerebbe essere in grado di modificare FilePath2 e Status con R utilizzando sqlUpdate() dal pacchetto RODBC. Così provo seguente:

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) 

cui db.df è un frame di dati con i nomi una riga e di colonna corrispondenti a quelli nella tabella di database (tuttavia, lascio alcune delle colonne, in questo caso FilePath1, e preferirei lasciare fuori anche ID1, se possibile). Il mio obiettivo è quello di ottenere il seguente:

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

ottengo l'errore folllowing:

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

Quale potrebbe essere la ragione di questo problema?


EDIT: Ho bypassato il problema con l'invio di una query SQL diretta:

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) 

Anche se questo potrebbe non essere un modo pulito, fa quello che dovrebbe fare. Tuttavia, non riesco ancora a capire qual è il problema con sqlUpdate, quindi spero che qualcuno possa far luce su di esso.

risposta

0

sqlUpdate ha funzionato per me. l'unica cosa che dovevo cambiare era il db.df - necessario per raddoppiare il carattere \ in modo che non provasse a sfuggire al codice con esso. La mia tabella di test si presentava così:

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

sono stato in grado di eseguire l'aggiornamento senza i campi ID1 o FilePath1 nell'aggiornamento. Se leggi la documentazione (? SqlUpdate) indica: 'Prima cerca una chiave primaria per la tabella, poi per la colonna (s) che il database considera ottimale per definire una riga in modo univoco' così tu don Devo usare la chiave primaria, anche se se non sapessi che ID2 era unico, sarebbe meglio usare quella chiave 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

ho sperimentato un problema simile quando si utilizza sqlUpdate per aggiornare una tabella in MySQL. L'ho risolto impostando gli attributi case nella connessione R-MySQL.

Ecco il dettaglio:

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

In 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 ragione è che il (default?) Attribuisce in connessione RMySQL ha:

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

Quindi, colname myName1 in myDF è cambiato caso di myname1 all'interno sqlUpdate, in modo che non corrisponde a myName1 data indice.

Si noti che non funzionerà se si cambia la chiamata con index = 'myname1'. Verrà segnalato un errore di index column(s) myName1 not in database table. Perché nella tabella MySQL, il nome è myName.

La soluzione è quella di impostare il caso attribuisce a 'NoChange' quando o dopo il collegamento:

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

Qui ci sono ulteriori dettagli:

debugonce(sqlUpdate) dà:

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 
    } 

Annotare il intable chiama allo cname e allo coldata.

0

In alcuni casi, specialmente se si passano più colonne, è necessario specificare esplicitamente la struttura della colonna come nomi di colonne.

Esempio: SQLUpdate (MyConn, db.df, nometabella = 'MyTable', indice = nomi ('ID2'), verbose = true)

Aggiornamento: Così sembra a volte non riesce ancora. Il nuovo lavoro che ho utilizzato è:

Ciò consente di passare un elenco di colonne, se necessario. Non so perché è stato schizzinoso dall'altra parte.

indexNames < -list ("ID2")

SQLUpdate (MyConn, db.df, nometabella = 'miatabella', index = as.character ("ID2"), verbose = TRUE)