В dplyr как работает sql builder? - PullRequest
0 голосов
/ 25 мая 2018

В R мы можем иметь следующее выражение:

tbl(con, "table1") %>% filter(col1 > 12)

, которое выполняет

select * from table1 where col1 > 12

Но если у вас есть tbl (con, "table1"), оно выполняет select *из таблицы.

Как первая функция tbl (con, "table1") знает, что к ней подключены дополнительные функции, и ей нужно дождаться завершения цепочки, прежде чем она соберет соответствующий запрос sql и выполниткоманда.Да, я знаю, что он использует ленивую оценку, но я не смог написать простой игрушечный пример, который будет таким же образом строить строку

т.е.

shoppingList("I need to get")

распечатка "Мне нужно ничего не получать "

и

shoppingList("I need to get") %>% item("apples") %>% item("oranges")

распечатка" Мне нужно получить яблоки и апельсины "

1 Ответ

0 голосов
/ 26 мая 2018

Возможно, вас смущает то, что функции dplyr tbl и filter фактически не отправляют какой-либо код в базу данных для выполнения.Когда вы запускаете

tbl(con, "table1") %>% filter(col1 > 12)

, возвращается объект tbl_dbi, содержащий SQL-запрос.Когда вы в интерактивном режиме запускаете эту строку кода в R, возвращенный объект tbl_dbi передается в функцию print.Чтобы распечатать tbl_dbi, запрос должен быть выполнен в базе данных.Вы можете убедиться в этом, сохранив вывод в переменную.

q <- tbl(con, "table1") %>% filter(col1 > 12)
class(q)

В двух приведенных выше строках ничего не было отправлено в базу данных.Функция tbl вернула объект tbl_dbi и фильтр изменил этот объект tbl_dbi.Наконец, результат был сохранен в переменную q.Когда мы печатаем q, тогда SQL отправляется в базу данных.Поэтому функции tbl не нужно знать о каких-либо других функциях dplyr, которые вызываются после нее (например, filter в этом случае).Он ведет себя одинаково, несмотря ни на что.Он всегда возвращает объект tbl_dbi.

Теперь, как dbplyr создает более сложные запросы из более простых, мне неизвестно.

Вот код, который реализует ваш пример.

library(dplyr)

shoppingList <- function(x){
     stopifnot(is.character(x))
     class(x) <- c("first", "shoppingList", class(x))
     x
}

item <- function(x, y){
     if("first" %in% class(x)){
          out <- paste(x, y)
     } else {
          out <- paste0(x, " and ", y)
     }
     class(out) <- c("shoppingList", class(out))
     out
}

print.shoppingList <- function(x){
     # code that only runs when we print an object of class shoppingList
     if("first" %in% class(x)) x <- paste(x, "nothing")
     print(paste0("***", x, "***"))
}

shoppingList("I need to get") 
#> [1] "***I need to get nothing***"

shoppingList("I need to get") %>% item("apples") %>% item("oranges")
#> [1] "***I need to get apples and oranges***"

Но как print узнает, как отправить SQL в базу данных?Мой (упрощенно) концептуальный ответ заключается в том, что print - это универсальная функция, которая будет вести себя по-разному в зависимости от класса переданного объекта. На самом деле существует множество print функций.В приведенном выше примере я создал специальную функцию печати для объектов класса shoppingList .Вы можете представить себе специальную функцию print.tbl_dbi, которая знает, как обрабатывать объекты tbl_dbi, отправляя запрос, который они содержат, в базу данных, к которой они подключаются, и затем печатая результат.Я думаю, что фактическая реализация более сложна, но, надеюсь, это даст некоторую интуицию.

...