Объединение dbplyr и case_when в SQL Server

Я использую dbplyr для написания и выполнения запросов в SQL Server и хочу применить условное изменение. Это можно сделать с помощью ifelse или case_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

Запуск этого кода вызывает ошибку

Выражение не-логического типа, указанное в контексте, где ожидается условие, рядом с '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-запросы? Есть предложения относительно того, что не так и как это исправить?

Обновлено

Размещено как проблема на tidyverse и проинформировано, что решение уже разработано для case_when(..., TRUE ~ "b") переводится на ELSE 'b' (здесь).

Однако, поскольку это не касается синтаксиса, вызывающего это исключение. Вопрос отредактирован, чтобы сосредоточиться на синтаксисе, который является причиной.

Обновление 2

Размещено как проблема на dbplyr. В ответе Кристофа Дервье (cderv) указано, что причина, по всей видимости, в том, что серверу SQL требуется специальный перевод для case_when, как и для ifelse.

Между тем, пользователи могут использовать несколько операторов ifelse или if_else.


person Simon.S.A.    schedule 23.08.2018    source источник
comment
Я также пробовал использовать ifelse вместо case_when, это дает: CASE WHERE (CONVERT(BIT, IIF(col1 = col2, 1.0, 0.0))) = TRUE) THEN ('a'), что действительно работает. Так, может быть, это ошибка?   -  person Simon.S.A.    schedule 23.08.2018
comment
Существует постоянный PR, в котором предлагается заменить WHEN(TRUE) предложением ELSE. Это должно решить вашу проблему.   -  person cderv    schedule 27.08.2018


Ответы (2)


Просто у вас немного неправильный синтаксис dplyr?

Попробуй это

# attempted query
tmp = my_table %>%
    mutate(new_col = case_when(col1 == col2 ~ "a",
                               col1 == 'TRUE' ~ "b"
              # alternatively  col1 == 1 ~ "b"
)) 
person Shinobi_Atobe    schedule 23.08.2018
comment
Извините, неправильный синтаксис dplyr был всего лишь опечаткой из-за моей попытки думать одновременно и в R, и в SQL (исправлено выше). Предложенный вами синтаксис по-прежнему производит тот же код SQL, который приводит к ошибке. - person Simon.S.A.; 23.08.2018
comment
Хм, это странно, потому что, похоже, это работает с моей базой данных ... может быть, это связано с тем, что логические значения хранятся в ваших таблицах? как они хранятся как текст "ИСТИНА" или 1/0? еще можно попробовать использовать if и else (не ifelse) - person Shinobi_Atobe; 24.08.2018
comment
ifelse работает правильно, а case_when - нет. Разница в том, что результирующий SQL, созданный ifelse, содержит на конце `= TRUE`, а SQL, созданный case_when, нет. - person Simon.S.A.; 25.08.2018
comment
Я не контролирую, как логические значения хранятся в базе данных. Я даже не знаю, как это проверить. - person Simon.S.A.; 25.08.2018

См. Обновление 2 выше:

Похоже, это проблема, влияющая на case_when для SQL-сервера.

В настоящее время обходной путь заключается в использовании нескольких операторов ifelse или if_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
person Simon.S.A.    schedule 13.09.2018