在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")
打印出“我需要得到苹果和橘子”
答案 0 :(得分: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对象,方法是将它们包含的查询发送到它们连接的数据库,然后打印结果。我认为实际的实现更复杂,但希望这提供了一些直觉。