2016-07-29 18 views
1

Ich habe gearbeitet, um eine SQL-Anweisung zu parametrisieren, die die IN-Anweisung in der WHERE-Klausel verwendet. Ich verwende rodbcext Bibliothek für die Parametrisierung, aber es scheint zu einer Erweiterung einer Liste zu fehlen.R RODBCext und IN-Anweisung parametrieren?

Ich hatte gehofft, Code, den ich verwende den folgenden Code wie

sqlExecute("SELECT * FROM table WHERE name IN (?)", c("paul","ringo","john", "george") 

zu schreiben, aber fragte sich, ob es einen einfacheren Weg.

library(RODBC) 
library(RODBCext) 

# Search inputs 
names <- c("paul", "ringo", "john", "george") 

# Build SQL statement 
qmarks <- replicate(length(names), "?") 
stringmarks <- paste(qmarks, collapse = ",") 
sql <- paste("SELECT * FROM tableA WHERE name IN (", stringmarks, ")") 
# expand to Columns - seems to be the magic step required 
bindnames <- rbind(names) 

# Execute SQL statement 
dbhandle <- RODBC::odbcDriverConnect(connectionString) 
result <- RODBCext::sqlExecute(dbhandle, sql, bindnames, fetch = TRUE) 
RODBC::odbcClose(dbhandle) 

es funktioniert, aber ich fühle mich R bin mit den Saiten in die falsche Art und Weise zu erweitern (Bit neu zu R - so viele Möglichkeiten, die gleiche Sache falsch zu tun). Jemand wird wahrscheinlich sagen "das schafft Faktoren - tu das nie" :-)

Ich fand diesen Artikel, der suggeriert, dass ich auf dem richtigen Weg bin, aber es diskutiert nicht, das "?" und drehen Sie die Liste in Spalten eines data.frame

R RODBC putting list of numbers into an IN() statement

Danke.

UPDATE: Wie Benjamin unten zeigt - die sqlExecute-Funktion kann eine Liste() von Eingaben verarbeiten. Bei der Überprüfung des resultierenden SQL habe ich jedoch festgestellt, dass es Cursor verwendet, um die Ergebnisse zusammenzufassen. Dies erhöht die CPU und I/O gegenüber dem obigen Beispielcode erheblich.

Während die Bibliothek kann dies tatsächlich für Sie lösen, für große Ergebnisse kann es zu teuer sein. Es gibt zwei Antworten und es hängt von Ihren Bedürfnissen ab.

+0

In PHP habe ich viel Code gesehen, der Variablen direkt in SQL-Anweisung setzt. Und wenn es funktioniert, warum sollte es dich interessieren? Nicht alle Dinge sind in R leicht zu machen. Und das ist das erste Mal, dass ich sehe, wie R sich mit einer Datenbank verbindet. –

+0

Verbinden mit Datenbanken ist eine der wichtigsten Funktionen von R – Carl

+0

Unter Tausenden – mdsumner

Antwort

1

Da Ihr nur Parameter in der Abfrage in der Sammlung ist für IN, könnten Sie mit

sqlExecute(dbhandle, 
    "SELECT * FROM table WHERE name IN (?)", 
    list(c("paul","ringo","john", "george")), 
    fetch = TRUE) 

sqlExecute weg werden die Werte in der Liste auf das Fragezeichen binden. Hier wird die Abfrage tatsächlich vier Mal wiederholt, einmal für jeden Wert im Vektor. Es mag irgendwie albern erscheinen, es auf diese Weise zu tun, aber wenn man versucht, Strings zu übergeben, ist es in vielerlei Hinsicht viel sicherer, die Bindung sich um die Einrichtung der passenden Anführungszeichenstruktur kümmern zu lassen, anstatt es selbst einzufügen. Sie werden auf diese Weise weniger Fehler generieren und viele Probleme mit der Datenbanksicherheit vermeiden.

+0

Ich werde das versuchen. Bei Verwendung von c() wurde ein Fehler über unbenutztes "cond" zurückgegeben und nur der erste Wert wurde verwendet ... aber vielleicht ist list() die Magie. Ich habe den Code auf GitHub gefunden und habe nichts Offensichtliches gesehen. Das Ausführen von 4 Anweisungen könnte in meinem Fall in Ordnung sein. – ripvlan

+2

Streng genommen will 'sqkExecute' einen Datenrahmen. Listen können einfach in Datenrahmen konvertiert werden. Außerdem werden Sie nicht bemerken, dass es vier Anrufe tätigt. 'sqlExecute' schleift über die Zeilen des Datenrahmens, extrahiert für jede Zeile einen Datenrahmen und bindet sie am Ende zusammen. Von der R-Seite wird es sich wie ein Anruf anfühlen, unabhängig davon, was auf der SQL-Seite passiert. – Benjamin

+0

Ja - danke. Das war ein Tippfehler, als ich meine Probe neu erstellte. Ich benutze ein data.frame ... data.frame (name = c ("john", ....) Was natürlich nicht funktioniert. – ripvlan