出现这个问题是因为我希望为方便起见创建一个函数:
as.numeric_psql <- function(x) {
return(as.numeric(as.integer(x)))
}
Run Code Online (Sandbox Code Playgroud)
将远程 postgres 表中的布尔值转换为数字。需要转换为整数的步骤如下:
在数字和布尔值之间没有定义直接转换。您可以使用整数作为中间立场。( /sf/answers/1350347001/ )
当然,此功能在本地按预期工作:
copy_to(con_psql, cars, 'tmp_cars')
tmp_cars_sdf <-
tbl(con_psql, 'tmp_cars')
tmp_cars_sdf %>%
mutate(low_dist = dist < 5) %>%
mutate(low_dist = as.numeric(as.integer(low_dist)))
# # Source: lazy query [?? x 3]
# # Database: postgres 9.5.3
# speed dist low_dist
# <dbl> <dbl> <dbl>
# 1 4 2 1
# 2 4 10 0
# 3 7 4 1
# 4 7 22 0
# 5 8 16 0
cars %>%
mutate(low_dist = dist < 5) %>%
mutate(low_dist = as.numeric_psql(low_dist)) %>%
head(5)
# speed dist low_dist
# 1 4 2 1
# 2 4 10 0
# 3 7 4 1
# 4 7 22 0
# 5 8 16 0
Run Code Online (Sandbox Code Playgroud)
但是,在远程数据帧上使用时它不起作用,因为as.numeric_psql它不在 sql 翻译列表中,因此被逐字传递给查询:
> tmp_cars_sdf %>%
+ mutate(low_dist = dist < 5) %>%
+ mutate(low_dist = as.numeric_psql(low_dist))
Error in postgresqlExecStatement(conn, statement, ...) :
RS-DBI driver: (could not Retrieve the result : ERROR: syntax error at or near "as"
LINE 1: SELECT "speed", "dist", as.numeric_psql("low_dist") AS "low_...
^
)
Run Code Online (Sandbox Code Playgroud)
我的问题是是否存在一种简单的方法(即不定义自定义 sql 翻译)让 dplyr 理解该函数as.numeric_psql是具有现有 sql 翻译的函数的组合,并改为使用这些翻译。
避免错误的一种方法是将函数设置为在数据帧上操作,而不是在内部 mutate 上操作。例如:
\n\ncopy_to(con_psql, cars, 'tmp_cars')\n\ntmp_cars_sdf <- tbl(con_psql, 'tmp_cars')\n\nas.numeric_psql <- function(data, x) {\n return(data %>% mutate({{x}} := as.numeric(as.integer({{x}}))))\n}\n\ntmp_cars_sdf %>%\n mutate(low_dist = dist < 5) %>%\n as.numeric_psql(low_dist)\n\n#> # Source: lazy query [?? x 3]\n#> # Database: sqlite 3.30.1 [:memory:]\n#> speed dist low_dist\n#> <dbl> <dbl> <dbl>\n#> 1 4 2 1\n#> 2 4 10 0\n#> 3 7 4 1\n#> 4 7 22 0\n#> 5 8 16 0\n#> 6 9 10 0\n#> 7 10 18 0\n#> 8 10 26 0\n#> 9 10 34 0\n#> 10 11 17 0\n#> # \xe2\x80\xa6 with more rows\nRun Code Online (Sandbox Code Playgroud)\n\n请注意,在您的示例中,数据库版本low_dist在创建时已被编码为整数,而不是像标准 R 数据框架中那样符合逻辑:
tmp_cars_sdf %>%\n mutate(low_dist = dist < 5) \n#> # Source: lazy query [?? x 3]\n#> # Database: sqlite 3.30.1 [:memory:]\n#> speed dist low_dist\n#> <dbl> <dbl> <int>\n#> 1 4 2 1\n#> 2 4 10 0\n#> 3 7 4 1\n#> 4 7 22 0\n#> 5 8 16 0\n#> 6 9 10 0\n#> 7 10 18 0\n#> 8 10 26 0\n#> 9 10 34 0\n#> 10 11 17 0\n#> # \xe2\x80\xa6 with more rows\n\ncars %>%\n mutate(low_dist = dist < 5) %>% head\n#> speed dist low_dist\n#> 1 4 2 TRUE\n#> 2 4 10 FALSE\n#> 3 7 4 TRUE\n#> 4 7 22 FALSE\n#> 5 8 16 FALSE\n#> 6 9 10 FALSE\nRun Code Online (Sandbox Code Playgroud)\n