如何在SQL Server中使用dplyr连接表中的多个列的字符串?

mxg2im7a  于 2023-04-18  发布在  SQL Server
关注(0)|答案(3)|浏览(117)

作为标题,我想从SQL Server中的一个表中连接几列,我尝试使用paste函数,如下所示,但给予以下错误:

> tbl(channel,'##iris') %>% 
+   mutate(string=paste(Species,'-',
+                       Sepal.Length,'-',
+                       Sepal.Width,'-',
+                       Petal.Length,'-',
+                       Petal.Width,sep=''))
Error: PASTE() is not available in this SQL variant
cgyqldqp

cgyqldqp1#

我发现了Ben Baumer提供的一个解决方案here,并想在这里分享。
方法是使用CONCAT而不是paste

> tbl(channel,'##iris') %>% 
+   group_by(Species,Sepal.Length,Sepal.Width,Petal.Length,Petal.Width) %>%
+   summarise(string=MAX(CONCAT(Species,'-',
+                               Sepal.Length,'-',
+                               Sepal.Width,'-',
+                               Petal.Length,'-',
+                               Petal.Width))) %>%
+   head(.,1)
# Source:   lazy query [?? x 6]
# Database: Microsoft SQL Server 11.00.6251[dbo@WCDCHCMSAH01\CMSAH_DC7_MP1/data_ha_amr]
# Groups:   Species, Sepal.Length, Sepal.Width, Petal.Length
  Species Sepal.Length Sepal.Width Petal.Length Petal.Width string              
  <chr>          <dbl>       <dbl>        <dbl>       <dbl> <chr>               
1 setosa          4.30        3.00         1.10       0.100 setosa-4.3-3-1.1-0.1
lb3vh1jj

lb3vh1jj2#

在R data.frames上使用tidyversetidyr::unite将是惯用的方法。
虽然不是一个dplyr动词,但它还没有被翻译为通过dbplyr/SQL使用。
您可以在SQL Server中以这种方式定义自己的unite(不幸的是,我无法测试,但它应该可以工作):

unite.tbl <- function (data, col, ..., sep = "_", remove = TRUE) 
{
  dot_names <- sapply(substitute(list(...))[-1], deparse)
  shown_cols <- if (remove) 
    setdiff(data$ops$vars, dot_names)
  else data$ops$vars
  shown_col_str <- paste(shown_cols, collapse = ", ")
  concat_str <- paste0("CONCAT(",paste(dot_names, collapse = paste0(",'",sep,"',")),")")
  col <- deparse(substitute(col))
  subquery <- capture.output(show_query(data), type = "message")[-1] %>% paste(collapse = " ")
  query    <- paste("SELECT",shown_col_str,",",concat_str,"AS",col,"FROM (",subquery,")")
  tbl(data$src$con, sql(query))
}

然后:

tbl(channel,'##iris') %>%
  unite(string,
        Species, Sepal.Length, Sepal.Width, Petal.Length, Petal.Width,
        sep = '',remove=FALSE)

对于支持||串联运算符的DBMS(例如Oracle),只需将concat_str定义替换为:

concat_str <- paste(dot_names, collapse = paste0(" || '", sep, "' || "))
jdgnovmf

jdgnovmf3#

我必须对@moodymudskipper的解决方案做一些小的修改才能让它工作。

unite.tbl <- function (data, col, ..., sep = "_", remove = TRUE) 
{
  # remove the list call
  dot_names <- sapply(substitute(...)[-1], deparse)
  shown_cols <- if (remove) 
    # replace $ops$vars with colnames
    setdiff(data %>% colnames(), dot_names)
  else data %>% colnames()
  shown_col_str <- paste(shown_cols, collapse = ", ")
  concat_str <- paste(dot_names, collapse = paste0(" || '", sep, "' || "))
  col <- deparse(substitute(col))
  # remove type arg
  subquery <- capture.output(show_query(data))[-1] %>% paste(collapse = " ")
  query    <- paste(
    "SELECT", shown_col_str, ",",
    concat_str, "AS", col,
    "FROM (",
    subquery,
    ")"
  )
  tbl(data$src$con, sql(query))
}

我需要为我的用例添加的是一种忽略NA和/或NULL的方法,就像来自tidyr::unitena.rm arg一样。
编辑:这里是带有na.rm参数的版本。我确实需要...周围的list Package 器。这可能需要适应Oracle以外的其他RDBMS。

unite.tbl <- function (data, col, ..., sep = "_", remove = TRUE, na.rm = FALSE) 
{
  dot_names <- sapply(substitute(list(...))[-1], deparse)
  shown_cols <- data %>% colnames()
  shown_cols <- `if`(
    remove,
    setdiff(shown_cols, dot_names),
    shown_cols
  )
  shown_col_str <- paste(shown_cols, collapse = ", ")
  concat_str <- ifelse(
    na.rm,
    paste0(
      paste0(
        "NVL2(",
        dot_names%>% head(-1), ", ",
        dot_names%>% head(-1), " || '", sep, "'", 
        ", '')", 
        collapse = " || "
      ),
      " || NVL(", dot_names%>% tail(1), ", '')"
    ),
    paste0(dot_names, collapse = paste0(" || '", sep, "' || "))
  )
  col <- deparse(substitute(col))
  subquery <- capture.output(show_query(data))[-1] %>% paste(collapse = " ")
  query    <- paste(
    "SELECT", shown_col_str, ",",
    concat_str, "AS", col,
    "FROM (",
    subquery,
    ")"
  )
  tbl(data$src$con, sql(query))
}

相关问题