2016-07-18 7 views
3

Im Zusammenhang mit https://stackoverflow.com/a/33284035/3358272, finde ich inkonsistente Verhalten beim Ziehen von Daten aus SQL Server (2014).RODBC: Chars und Numerik aggressiv konvertiert (mit/ohne as.is)

library(RODBC) 
sqlQuery(.conn, "CREATE TABLE r2test ([mychar] [NVARCHAR](16), [mynum] [FLOAT])") 
# character(0) 
sqlQuery(.conn, "INSERT INTO r2test (mychar,mynum) VALUES ('1',3.141593),('2',6.283185)") 
character(0) 
str(sqlQuery(.conn, "SELECT * FROM r2test", stringsAsFactors = FALSE)) 
# 'data.frame': 2 obs. of 2 variables: 
# $ mychar: int 1 2 
# $ mynum : num 3.14 6.28 

In diesem Beispiel sehen wir das unerwünschte Verhalten: Die Zeichen von mychar werden intern auf ganze Zahlen umgewandelt werden. Per die zuvor erwähnte SO beantworten, die as.is Option besiegt dies, hat aber den unglücklichen Nebeneffekt auch dezimal repräsentiert Schwimmer in Strings zu zwingen:

str(sqlQuery(.conn, "SELECT * FROM r2test", stringsAsFactors = FALSE, as.is = TRUE)) 
# 'data.frame': 2 obs. of 2 variables: 
# $ mychar: chr "1" "2" 
# $ mynum : chr "3.1415929999999999" "6.2831849999999996" 

Wenn mindestens einer der mychar eigentlich nicht integer-izable ist , sind die Dinge in Ordnung:

sqlQuery(.conn, "INSERT INTO r2test (mychar,mynum) VALUES ('a',9.424778)") 
# character(0) 
str(sqlQuery(.conn, "SELECT * FROM r2test", stringsAsFactors = FALSE)) 
# 'data.frame': 3 obs. of 2 variables: 
# $ mychar: chr "1" "2" "a" 
# $ mynum : num 3.14 6.28 9.42 

Leider ist das Datenmodell nicht willkürlich etwas unterstützt das Hinzufügen dieses Verhalten zu fördern (oder ich habe einfach nicht daran gedacht, eine ausreichend gute Art und Weise, es zu tun). Das Datenmodell ist derart, dass Werte von mychar01 und 1 umfassen, die zeichenweise verschieden sind. Die einzige Problemumgehung, die ich gefunden habe, ist, as.is = TRUE zu verwenden, die mich zu as.numeric alle verwandten Spalten benötigen wird, etwas, das sowohl langweilige als auch (theoretisch) unnötige Arbeit ist.

Da die Dokumente zu setzen DBMSencoding empfehlen benötigen, überprüfte ich die aktuelle Codierung (unterstützt von https://stackoverflow.com/a/5182469/3358272):

sqlQuery(.conn, "SELECT SERVERPROPERTY('Collation')") 
# 1 SQL_Latin1_General_CP1_CI_AS 

Ich habe versucht, mit (für Kicks): DBMSencoding="latin1", DBMSencoding="UTF-8" und explizit obwohl der Standard DBMSencoding="" ohne Verhaltensänderung.

Wie kann ich das Verhalten ermutigen, die Datentypen nicht zu übersteuern?

Derzeit mit R-3.2.5 und RODBC-1.3.13 auf Ubuntu.

Antwort

4

Wenn ich richtig verstehe, ich denke, das wenn das, was Sie suchen,

str(sqlQuery(
    .conn, 
    "SELECT * FROM r2test", 
    stringsAsFactors = FALSE, 
    as.is = c(TRUE, FALSE) 
)) 
#'data.frame': 2 obs. of 2 variables: 
# $ mychar: chr "1" "2" 
# $ mynum : num 3.14 6.28 

wo as.is als logischen Vektor angegeben wird (muss die gleiche Länge wie die Anzahl der Spalten in der Ergebnismenge hat) . Um fair zu sein, wird dies nicht wirklich gut dargelegt. Die man-Seite für sqlQuery verweist nur auf die as.is Argument in read.table, in dem es heißt:

Beachten Sie, dass as.is pro Spalte (nicht pro Variable) und so enthält die Spalte der Zeilennamen (falls vorhanden) und alle Spalten übersprungen werden.

Der Nachteil dieses Ansatzes ist, dass Sie im Voraus wissen müssen, welche Spalten Sie konvertieren möchten und welche nicht. Persönlich sehe ich nicht warum das Standardverhalten ist nicht nur SQL-Zeichentypen auf R Zeichentypen zuordnen, SQL numerische Typen zu R numerischen Typen, etc., aber vielleicht gibt es einen guten Grund dafür auf dem Backend. Automatisch konvertieren '1', '2', ... zu ganzen Zahlen tut nicht scheinen wie viel von einem "Feature" für mich.

+1

Ich hatte nicht in Betracht gezogen, einen logischen * Vektor * zu verwenden, der die Dinge ein wenig verbessert und einen direkteren Ausweg bietet, danke! Einverstanden auf das "sehe nicht warum", aber andererseits biete ich (noch) nicht an, Code zu schreiben (und eine PR einzureichen), um die Dinge anders zu behandeln. – r2evans

+0

Ja, es ist etwas verwirrend, wenn Funktionsargumente einen Standardwert von 'TRUE' oder 'FALSE' haben, aber auch einen logischen * Vektor * akzeptieren. Und außerdem, ich habe eine langjährige Knochen zu wählen mit diesem Paket über 'sqlUpdate' funktioniert nicht wie angekündigt, aber ich habe noch nicht zu arbeiten auf einem Patch, so dass ich nicht zu laut beschweren kann ... – nrussell

+1

nrussell , außer * R-sigs-db *, kennst du noch ein anderes RODBC-spezifisches Diskussionsforum? Quellcode für Probleme und PRs? Ich würde gerne Dinge wie parametrisierte Abfragen, Partialtabellen 'sqlSave' und andere Dinge diskutieren, die meine Verwendung von RODBC unnötig einschränken. – r2evans