在dplyr中,sql builder如何工作?

时间:2018-05-25 18:36:01

标签: r dplyr dbplyr

在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 :(得分:1)

令你困惑的是,dplyr函数tblfilter实际上并没有将任何代码发送到数据库以供执行。当你运行

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

返回的是包含sql查询的tbl_dbi对象。当您在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对象,方法是将它们包含的查询发送到它们连接的数据库,然后打印结果。我认为实际的实现更复杂,但希望这提供了一些直觉。