在 dplyr 中,sql 构建器如何工作?
In dplyr how does the sql builder work?
在R中,我们可以有如下表达式:
tbl(con, "table1") %>% filter(col1 > 12)
执行
select * from table1 where col1 > 12
但是如果你有 tbl(con, "table1"),它会从 table.
执行 select *
第一个函数 tbl(con, "table1") 如何知道它有附加函数链接到它,并且需要等待链结束才能构建正确的 sql 查询并执行命令。是的,我知道它使用惰性求值,但我无法编写一个简单的玩具示例来以相同的方式构建字符串
即
shoppingList("I need to get")
打印出来"I need to get nothing"
和
shoppingList("I need to get") %>% item("apples") %>% item("oranges")
打印出来"I need to get apples and oranges"
也许让您感到困惑的是 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
)。无论如何,它的行为都是一样的。它总是 returns 一个 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
是一个通用函数,其行为会根据传入对象的 class 而有所不同。实际上有很多 print
函数。在上面的示例中,我为 class shoppingList 的对象创建了一个特殊的打印函数。您可以想象一个特殊的 print.tbl_dbi
函数,它知道如何处理 tbl_dbi 对象,方法是将它们包含的查询发送到它们连接的数据库,然后打印结果。我认为实际的实现更复杂,但希望这能提供一些直觉。
在R中,我们可以有如下表达式:
tbl(con, "table1") %>% filter(col1 > 12)
执行
select * from table1 where col1 > 12
但是如果你有 tbl(con, "table1"),它会从 table.
执行 select *第一个函数 tbl(con, "table1") 如何知道它有附加函数链接到它,并且需要等待链结束才能构建正确的 sql 查询并执行命令。是的,我知道它使用惰性求值,但我无法编写一个简单的玩具示例来以相同的方式构建字符串
即
shoppingList("I need to get")
打印出来"I need to get nothing"
和
shoppingList("I need to get") %>% item("apples") %>% item("oranges")
打印出来"I need to get apples and oranges"
也许让您感到困惑的是 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
)。无论如何,它的行为都是一样的。它总是 returns 一个 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
是一个通用函数,其行为会根据传入对象的 class 而有所不同。实际上有很多 print
函数。在上面的示例中,我为 class shoppingList 的对象创建了一个特殊的打印函数。您可以想象一个特殊的 print.tbl_dbi
函数,它知道如何处理 tbl_dbi 对象,方法是将它们包含的查询发送到它们连接的数据库,然后打印结果。我认为实际的实现更复杂,但希望这能提供一些直觉。