2013-07-19 12 views
6

Sto provando a estrarre dati da un database PostgreSQL e i risultati per un campo data/ora sono incoerenti. Non sono sicuro di gestire correttamente i risultati POSIXct. Altrimenti, penso di aver trovato un bug nel pacchetto RPostgreSQL. Ecco il modo per replicare il problema:Esiste un modo specifico per gestire le colonne di timestamp in R quando si estraggono dati utilizzando RPostgreSQL?

Supponiamo che ci sia una tabella di un database Postgres con un campo (eseguire questo in PostgreSQL):

CREATE DATABASE mydb; 
CREATE TABLE test_table 
( 
    "DateTime" timestamp without time zone NOT NULL, 
    CONSTRAINT "pk_test_table" PRIMARY KEY ("DateTime") 
) 
WITH (
    OIDS=FALSE 
); 
ALTER TABLE test_table 
    OWNER TO postgres; 

E diciamo ci sono poche centinaia di record. Io li popolerà in R. Ecco il codice:

library(RPostgreSQL) 

# Let's feed the table with some sequence of date/time values 
date_values <- as.chron(seq(10000, 10500, 1/24)) 

format.chron <- function(z) { 
    sprintf("%04.0f-%02.0f-%02.0f %02.0f:%02.0f:00", 
      as.numeric(as.character(years(z))), 
      months(z), 
      as.numeric(as.character(days(z))), 
      as.numeric(as.character(hours(z))), 
      as.numeric(as.character(minutes(z)))) 
} 

.generateInsertQuery <- function(date_values, field_name, table_name) { 
    insert_val <- paste(paste0("(", sQuote(format(date_values)), ")"), collapse=',') 
    qry   <- paste("INSERT INTO", dQuote(table_name), paste0("(", dQuote(field_name), ")"), "VALUES", insert_val) 
    qry 
} 

drv <- dbDriver('PostgreSQL') 
con <- dbConnect(drv, user='postgres', dbname='mydb') 
qry <- .generateInsertQuery(date_values, "DateTime", "test_table") 
dbSendQuery(con, qry) 

Se provo ad ottenere i valori, la componente temporale viene spogliato fuori dei dati risultanti

res <- dbGetQuery(con, "SELECT * FROM test_table") 
res[1:20,1] 

La classe del risultato, tuttavia, è POSIXct

class(res[,1]) 

Se il risultato è prelevato un record alla volta, i valori con ore: min pari a 00:00 perdere la componente temporale:

012.
rs <- dbSendQuery(con, "SELECT \"DateTime\" FROM test_table") 
res_list <- list() 
for(i in 1:100) res_list[i] <- fetch(rs,1) 
res_list 

Come soluzione temporanea, sto recuperando il risultato 1 record alla volta, correggendolo e aggregandoli in un data.frame. Ma questo richiede molto tempo, soprattutto per i grandi set di dati. Qualche idea sul perché questo sta accadendo e su come affrontare questo problema?

Grazie in anticipo!

+0

Come accennato in precedenza, l'uso di 'timestamp with timezone' nell'istruzione' CREATE TABLE' ha fatto il trucco per me.Anche se non è davvero parte della domanda, nella mia esperienza ho trovato che 'dbWriteTable' non ama ** qualsiasi ** maiuscola quando si specificano i nomi delle tabelle SQL su cui scrivere. – bibzzzz

risposta

3

Prima di tutto, il progetto RPostgreSQL ha una mailing list; Ti suggerisco di postare lì.

PostgreSQL ha due tipi di datetime: con e senza fuso orario. Come ricordo, R mappa solo quest'ultimo. Ho scritto alcuni primi test di regressione per questo (vedi la fonte del pacchetto) ma non sono stato coinvolto nel progetto in ritardo. Ma ricordo che POSIXct esegue il mapping avanti e indietro con il tipo datetime PostgreSQL.

+0

Grazie a @Dirk per il suggerimento. Nel mio caso, sto utilizzando il timestamp senza timezone e sto ancora riscontrando il problema sopra descritto. Proverò la mailing list. – JAponte

+1

Provare 'timestamp con timezone' e vedere se funziona. Puoi sempre utilizzare l'UTC come fuso orario. –

+0

Grazie ancora per il suggerimento @Dirk. Sono stato in grado di spingere e tirare un lungo vettore di valori POSIXlt dal 2000 al 2010 senza alcun problema. Quindi sembra che il timestamp senza fuso orario sia il tipo non supportato. Questo è ancora meglio, poiché il mio precedente approccio era ambiguo in termini di fuso orario, il che poteva creare confusione tra gli utenti dei dati. – JAponte

4

RPostgreSQL di dbWriteTable con qualsiasi campo posixct creerà campo di database di tipo timestamp with timezone sempre con tz +00 non importa quale fuso orario posixct sarà. Credo che sarebbe più preciso creare timestamp without timezone.

La soluzione migliore sia per dbReadTable sia per dbWriteTable utilizza Sys.setenv(TZ = "UTC"). Secondo me è una dipendenza troppo profonda perché molti altri processi nella sessione R potrebbero richiedere un'impostazione corretta del fuso orario.

Molto più specifico e non profonda dipendente è definire proprio dbReadTable e dbWriteTable che avvolge la versione DBI con adeguate preelaborazione/postelaborazione dei tipi posixct. Ma ancora non è un'opzione se si sta sviluppando codice/pacchetto DBI-compatibile (non solo postgres correlati).

Sarebbe bello avere RPostgreSQL migrato su github per un contributo più semplice.

+2

Vedi il nuovo progetto RPostgres che vive su GitHub ... – hadley