1

在 R 中,我们可以有以下表达式:

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

执行

select * from table1 where col1 > 12

但是如果你有 tbl(con, "table1"),它会执行 select * from table。

第一个函数 tbl(con, "table1") 如何知道它有链接到它的附加函数,并且需要等待链结束才能构建正确的 sql 查询并执行命令。是的,我知道它使用惰性求值,但是我无法编写一个简单的玩具示例来以相同的方式构建一个字符串

IE

shoppingList("I need to get")

打印出“我什么都不需要”

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

打印出“我需要买苹果和橘子”

4

1 回答 1

1

也许让您感到困惑的是 dplyr 函数tbl并且filter实际上并没有将任何代码发送到数据库以供执行。当你跑

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

于 2018-05-26T15:49:58.477 回答