在 SQL 服务器中结合 dbplyr 和 case_when

Combining dbplyr and case_when in SQL Server

我正在使用 dbplyr 在 SQL 服务器中编写和 运行 查询,并希望应用条件变异。这可以使用 ifelsecase_when 来完成。该查询在使用 ifelse 时有效,但在使用 case_when.

时抛出异常

问题似乎是这两个命令被翻译成的 SQL 语法。 case_when 语法似乎无效 SQL。你能告诉我为什么以及如何解决它吗?或者这是一个错误?

# libraries
library(DBI)
library(dplyr)
library(dbplyr)

# establish connection to database table
connection_string = "database.specific.string"
# mine looks something like "DRIVER=...; Trusted_Connection=...; DATABASE=...' SERVER=..."
db_connection = dbConnect(odbc::odbc(), .connection_string = connection_string)
my_table = tbl(db_connection, from = my_table_name)

# attempted query
tmp = my_table %>%
    mutate(new_col = case_when(col1 == col2 ~ "a",
                               col1 != col2 ~ "b"))

# check SQL code for query
show_query(tmp)

生成的 SQL 查询是:

SELECT 
    col1, col2,
    CASE
       WHEN CONVERT(BIT, IIF(col1 = col2, 1.0, 0.0))) THEN ('a')
       WHEN CONVERT(BIT, IIF(col1 <> col2, 1.0, 0.0))) THEN ('b')
    END AS new_col
FROM my_database.my_table_name

运行 此代码抛出错误

An expression of non-boolean type specified in a context where a condition is expected, near 'THEN'

但是 ifelse 查询按预期工作:

# attempted query
tmp = my_table %>%
    mutate(new_col = ifelse(col1 == col2, "a", "b"))

# check SQL code for query
show_query(tmp)

生成的 SQL 查询是:

SELECT 
    col1, col2,
    CASE
       WHEN (CONVERT(BIT, IIF(col1 = col2, 1.0, 0.0))) = TRUE) THEN ('a')
       WHEN (CONVERT(BIT, IIF(col1 = col2, 1.0, 0.0))) = FALSE) THEN ('b')
    END AS new_col
FROM my_database.my_table_name

请注意,在这两种情况下,SQL 语法都是使用 show_query 生成的。使用 translate_sql 生成 SQL 代码始终如一地生成更清晰的 SQL 语法,但这不是在服务器上获得 运行 的语法。

还有其他人收到这些 SQL 查询吗?关于哪里出了问题以及如何解决这个问题有什么建议吗?

已更新

发布为 issue on the tidyverse and was informed that a solution has already been developed for case_when(..., TRUE ~ "b") being translated to ELSE 'b' (here)。

但是,因为这没有解决导致此异常的语法。编辑问题以关注引起问题的语法。

更新 2

作为 issue on dbplyr 发布。来自 Christophe Dervieux (cderv) 的响应表明原因似乎是 SQL 服务器需要对 case_when 进行特殊翻译,就像它对 ifelse.

所做的一样

同时,用户可以使用多个 ifelseif_else 语句。

是否只是您的 dplyr 语法有点错误?

试试这个

# attempted query
tmp = my_table %>%
    mutate(new_col = case_when(col1 == col2 ~ "a",
                               col1 == 'TRUE' ~ "b"
              # alternatively  col1 == 1 ~ "b"
)) 

参见上面的更新 2:

这似乎是一个影响 SQL 服务器的 case_when 的问题。

目前的解决方法是使用多个 ifelseif_else 语句:

data %>%
    mutate(new_col = ifelse(condition1, val1, NA)) %>%
    mutate(new_col = ifelse(is.na(new_col) & condition2, val2, new_col)) %>%
    mutate(new_col = ifelse(is.na(new_col) & condition3, val3, new_col))
    # etc