Skip to content

use **try_cast** instead of **cast** with Microsoft SQL (2012 and later) #380

@DavidPatShuiFong

Description

@DavidPatShuiFong

A failure to cast (e.g. as.numeric or as.double, when the string contains a non-numeric character) results in an error:

> library(magrittr)
> x <- mtcars %>% dplyr::mutate(wt = as.character(wt))
> x[1,6] <- "<2.62" # adds a non-numeric character '<' to an element
> DBI::dbWriteTable(con, "##mtcars", x) # where 'con' is an already defined connection to a MSSQL database
> con %>% dplyr::tbl("##mtcars") %>% dplyr::mutate(wt = as.numeric(wt))
Error: <SQL> 'SELECT TOP(11) "mpg", "cyl", "disp", "hp", "drat", CAST("wt" AS NUMERIC) AS "wt", "qsec", "vs", "am", "gear", "carb"
FROM "##mtcars"'
  nanodbc/nanodbc.cpp:1587: 42000: [Microsoft][ODBC SQL Server Driver][SQL Server]Error converting data type varchar to numeric. 

For Microsoft SQL (2012 and later) try_cast allows a more graceful return of NA. In dbplyr 1.4.2, this can be done by changing lines 225-232 in translate-sql-helpers.R (but this will probably only work for Microsoft SQL 2012 and later):

#' @rdname sql_variant
#' @export
sql_cast <- function(type) {
  type <- sql(type)
  function(x) {
    sql_expr(try_cast(!!x %as% !!type))
  }
}

...which results in a more graceful failure (returns NA):

> con %>% dplyr::tbl("##mtcars") %>% dplyr::mutate(wt = as.numeric(wt))
# Source:   lazy query [?? x 11]
# Database: Microsoft SQL Server 12.00.2000[bpsrawdata@DAVIDLENOVOPC\BPSINSTANCE/BPSSAMPLES]
     mpg   cyl  disp    hp  drat    wt  qsec    vs    am  gear  carb
   <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
 1  21       6  160    110  3.9     NA  16.5     0     1     4     4
 2  21       6  160    110  3.9      3  17.0     0     1     4     4
 3  22.8     4  108     93  3.85     2  18.6     1     1     4     1
 4  21.4     6  258    110  3.08     3  19.4     1     0     3     1
 5  18.7     8  360    175  3.15     3  17.0     0     0     3     2
 6  18.1     6  225    105  2.76     3  20.2     1     0     3     1
 7  14.3     8  360    245  3.21     4  15.8     0     0     3     4
 8  24.4     4  147.    62  3.69     3  20       1     0     4     2
 9  22.8     4  141.    95  3.92     3  22.9     1     0     4     2
10  19.2     6  168.   123  3.92     3  18.3     1     0     4     4
# ... with more rows

Is it possible to re-define sql_cast for Microsoft SQL backends only?

Metadata

Metadata

Assignees

No one assigned

    Labels

    featurea feature request or enhancementfunc trans 🌍Translation of individual functions to SQLhelp wanted ❤️we'd love your help!

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions