From bf3306989764d6cc1a3c14cc881ca9d91146dc5b Mon Sep 17 00:00:00 2001 From: David Fong Date: Sat, 19 Sep 2020 22:54:48 +1000 Subject: [PATCH] MSSQL version 11+ (2012+) backend calls try_cast instead of cast try_cast results in a more elegant failure (returns NA) if a cast is not possible ('cast' will throw an error). Address issue tidyverse#380 --- R/backend-mssql.R | 26 ++++++++++++++++++++++++-- R/translate-sql-helpers.R | 10 ++++++++++ 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/R/backend-mssql.R b/R/backend-mssql.R index 1b512103c..6870b4341 100644 --- a/R/backend-mssql.R +++ b/R/backend-mssql.R @@ -47,7 +47,7 @@ #' @export `sql_translate_env.Microsoft SQL Server` <- function(con) { - sql_variant( + mssql_scalar <- sql_translator(.parent = base_odbc_scalar, `!` = function(x) { @@ -150,8 +150,30 @@ sql_expr(DATEPART(QUARTER, !!x)) } }, + ) - ), + if (sub("0.*", "", DBI::dbGetInfo(con)$db.version) >= 11) { + # version 11 equates to MSSQL 2012 + # if MSSQL 2012+, use sql_try_cast, allows more graceful return of invalid values + mssql_scalar <- sql_translator(.parent = mssql_scalar, + as.logical = sql_try_cast("BIT"), + + as.Date = sql_try_cast("DATE"), + as.POSIXct = sql_try_cast("TIMESTAMP"), + as.numeric = sql_try_cast("FLOAT"), + as.double = sql_try_cast("FLOAT"), + as.integer = sql_try_cast("NUMERIC"), + # in MSSQL, NUMERIC converts to integer + as.integer64 = sql_try_cast("BIGINT"), + as.character = sql_try_cast("VARCHAR(MAX)"), + + as_date = sql_try_cast("DATE"), + as_datetime = sql_try_cast("DATETIME2") + ) + } + + sql_variant( + mssql_scalar, sql_translator(.parent = base_odbc_agg, sd = sql_aggregate("STDEV", "sd"), var = sql_aggregate("VAR", "var"), diff --git a/R/translate-sql-helpers.R b/R/translate-sql-helpers.R index c023c1dc7..22da5c41c 100644 --- a/R/translate-sql-helpers.R +++ b/R/translate-sql-helpers.R @@ -231,6 +231,16 @@ sql_cast <- function(type) { } } +#' @rdname sql_variant +#' @export +sql_try_cast <- function(type) { + type <- sql(type) + function(x) { + sql_expr(try_cast(!!x %as% !!type)) + # try_cast available in MSSQL 2012+ + } +} + #' @rdname sql_variant #' @export sql_log <- function() {