r和dplyr:如何使用compute()从不同于源模式的sql查询中创建持久表?

dluptydi  于 2021-07-26  发布在  Java
关注(0)|答案(2)|浏览(345)

我有一个类似于这篇文章的问题。
如何从数据库中的sql查询创建持久表(我使用db2数据库)?我的目标是使用一个模式中的表,并在另一个模式中永久地创建一个或多或少修改过的表。
到目前为止,有效的方法是将数据拉到 R 然后在不同的模式中创建一个表:

dplyr::tbl(con, in_schema("SCHEMA_A", "TABLE")) %>%
collect() %>% 
DBI::dbWriteTable(con, Id(schema = "SCHEMA_B", table = "NEW_TABLE"), ., overwrite = TRUE)

不过,我想把 compute() 函数 dplyr 管道,这样我就不必将数据拉入r,也就是说,我希望将数据保存在数据库中。作为旁注:我不知道如何替换 DBIdbWriteTable() 为了 dplyrcopy_to() –能够做到这一点也会对我有所帮助。
不幸的是,我不能使它工作,即使在阅读 ?compute() 以及它的在线文档。以下代码框架不起作用并导致错误:

dplyr::tbl(con, in_schema("SCHEMA_A", "TABLE")) %>%
dplyr::compute(in_schema("SCHEMA_B", "NEW_TABLE"), analyze = FALSE, temporary = FALSE)

有没有解决办法 compute() 或者适用于dplyr管道的其他解决方案?

nfg76nw0

nfg76nw01#

我使用一个自定义函数,该函数在远程表后面接收sql查询,将其转换为可以在sql服务器上执行的查询以保存新表,然后使用dbi包执行该查询。下面是关键细节,这里是github存储库中的完整细节(以及其他有用的功能)。

write_to_database <- function(input_tbl, db_connection, db, schema, tbl_name){
  # SQL query
  sql_query <- glue::glue("SELECT *\n",
                          "INTO {db}.{schema}.{tbl_name}\n",
                          "FROM (\n",
                          dbplyr::sql_render(input_tbl),
                          "\n) AS from_table")

  # run query
  DBI::dbExecute(db_connection, as.character(sql_query))
}

这个想法的本质是构造一个sql查询,如果您直接用数据库语言执行它,它将为您提供所需的结果。在我的申请表中,它采用以下形式:

SELECT *
INTO db.schema.table
FROM (
  /* sub query for existing table */
) AS alias

请注意,这是在使用SQLServer,您的特定sql语法可能会有所不同。 INTO 是用于写入表的sql server模式。在问题中链接到的示例中,语法是 TO TABLE .

hgqdbh6s

hgqdbh6s2#

感谢@simon.s.a.,我可以解决我的问题。正如他在回复中所显示的,可以定义一个自定义函数并将其合并到 dplyr 管道。我的代码如下所示:


# Custom function

write_to_database <- function(input_tbl, db_connection, schema, tbl_name){

  # SQL query

  sql_query <- glue::glue("CREATE TABLE {schema}.{tbl_name} AS (\n",
                      "SELECT * FROM (\n",
                      dbplyr::sql_render(input_tbl),
                      "\n)) WITH DATA;")

  # Drop table if it exists

  DBI::dbExecute(con, glue::glue("BEGIN\n",
                                    "IF EXISTS\n",
                                      "(SELECT TABNAME FROM SYSCAT.TABLES WHERE TABSCHEMA = '{schema}' AND TABNAME = '{tbl_name}') THEN\n",
                                        "PREPARE stmt FROM 'DROP TABLE {schema}.{tbl_name}';\n",
                                        "EXECUTE stmt;\n", 
                                    "END IF;\n",
                                 "END"))

  # Run query

  DBI::dbExecute(db_connection, as.character(sql_query))
}

# Dplyr pipeline

dplyr::tbl(con, in_schema("SCHEMA_A", "SOURCE_TABLE_NAME")) %>%
  dplyr::filter(VARIABLE == "ABC") %>% 
  show_query() %>% 
  write_to_database(., con, "SCHEMA_B", "NEW_TABLE_NAME")

结果是db2似乎不知道 DROP TABLE IF EXISTS 因此,一些额外的编程是必要的。我用这个堆垛机把它弄好了。此外,在我的例子中,我不需要显式地指定数据库,以便 db 在中,自定义函数被省略。

相关问题