Evaluación no estándar (NSE) en dplyr’s filter_ & pulling data from MySQL

Me gustaría obtener algunos datos de un servidor sql con un filtro dynamic. Estoy usando el gran paquete R dplyr de la siguiente manera:

#Create the filter filter_criteria = ~ column1 %in% some_vector #Connect to the database connection <- src_mysql(dbname <- "mydbname", user <- "myusername", password <- "mypwd", host <- "myhost") #Get data data % tbl("mytable") %>% #Specify which table filter_(.dots = filter_criteria) %>% #non standard evaluation filter collect() #Pull data 

Esta pieza de código funciona bien, pero ahora me gustaría bifurcarla de alguna manera en todas las columnas de mi tabla, así que me gustaría escribir el filtro como:

 #Dynamic filter i <- 2 #With a loop on this i for instance which_column <- paste0("column",i) filter_criteria <- ~ which_column %in% some_vector 

Y luego vuelva a aplicar el primer código con el filtro actualizado.

Lamentablemente, este enfoque no da los resultados esperados. De hecho, no da ningún error, pero ni siquiera extrae ningún resultado en R. En particular, analicé un poco la consulta SQL generada por los dos fragmentos de código y existe una diferencia importante.

Mientras que el primer código que funciona genera una consulta del formulario:

 SELECT ... FROM ... WHERE `column1` IN .... 

(`ingrese el nombre de la columna), el segundo genera una consulta del formulario:

 SELECT ... FROM ... WHERE 'column1' IN .... 

(‘ingrese el nombre de la columna)

¿Alguien tiene alguna sugerencia sobre cómo formular la condición de filtrado para que funcione?

No está realmente relacionado con SQL. Este ejemplo en R tampoco funciona:

 df < - data.frame( v1 = sample(5, 10, replace = TRUE), v2 = sample(5,10, replace = TRUE) ) df %>% filter_(~ "v1" == 1) 

No funciona porque necesita pasar para filter_ la expresión ~ v1 == 1 – no la expresión ~ "v1" == 1 .

Versión dplyr> = 0.6

Para resolver el problema, simplemente use el operador quoting y el operador de dequoting.

 library(dplyr) which_column = quot(v1) df %>% filter(!!which_column == 1) 

Versión dplyr <0.6

Para resolver el problema, use la función interp del paquete lazyeval.

 library(lazyeval) filter_criteria < - interp(~ which_column == 1, which_column = as.name("v1")) df %>% filter_(filter_criteria) 

Aquí hay una solución ligeramente menos detallada y una que usa el comportamiento típico de la función de extracción, '[' al seleccionar una columna por valor de carácter en lugar de convertirla en un elemento de idioma:

 df %>% filter(., '['(., which_column)==1 ) set.seed(123) df < - data.frame( v1 = sample(5, 10, replace = TRUE), v2 = sample(5,10, replace = TRUE) ) which_column <- "v1" df %>% filter(., '['(., which_column)==1) # v1 v2 #1 1 5 

Una solución alternativa, con la versión 0.5.0 de dplyr (probablemente implementada antes que eso), es posible pasar una cadena compuesta como el argumento .dots, que me parece más legible que la solución lazyeval :: interp:

 df < - data.frame( v1 = sample(5, 10, replace = TRUE), v2 = sample(5,10, replace = TRUE) ) which_col <- "v1" which_val <- 1 df %>% filter_(.dots= paste0(which_col, "== ", which_val)) v1 v2 1 1 1 2 1 2 3 1 4 

ACTUALIZACIÓN para dplyr 0.6:

 packageVersion("dplyr") # [1] '0.5.0.9004' df %>% filter(UQ(rlang::sym(which_col))==which_val) #OR df %>% filter((!!rlang::sym(which_col))==which_val) 

(Similar a la respuesta de @Matthew para dplyr 0.6, pero asumo que which_col es una variable de cadena.)