【问题标题】:How to write virtual BQ table back to BQ using R DBI and bigrquery?如何使用 R DBI 和 bigrquery 将虚拟 BQ 表写回 BQ?
【发布时间】:2020-11-11 19:26:40
【问题描述】:

我希望能够

  1. 访问 BQ 表。这是课
[1] "tbl_BigQueryConnection" "tbl_dbi"                "tbl_sql"               
[4] "tbl_lazy"               "tbl"   `
  1. 使用 dbplyr 更改表以创建新表。再次,上课
[1] "tbl_BigQueryConnection" "tbl_dbi"                "tbl_sql"               
[4] "tbl_lazy"               "tbl"   
  1. 将此新表写入 BQ。

我收到以下错误:

(函数(类,fdef,mtable)中的错误: 无法找到签名“BigQueryConnection”、“character”、“tbl_BigQueryConnection”的函数“dbWriteTable”的继承方法

MRE

library(DBI)
library(dplyr, warn.conflicts = FALSE)
library(bigrquery)

############  CREATE BQ TABLE TO ACCESS  #################
dataset = bq_dataset(bq_test_project(), "test_dataset")

if (bq_dataset_exists(dataset))
{
  bq_dataset_delete(dataset, delete_contents = T)
}
#> Suitable tokens found in the cache, associated with these emails:
#>   * ariel.balter@gmail.com
#>   * ariel.balter@providence.org
#> The first will be used.
#> Using an auto-discovered, cached token.
#> To suppress this message, modify your code or options to clearly consent to the use of a cached token.
#> See gargle's "Non-interactive auth" vignette for more details:
#> https://gargle.r-lib.org/articles/non-interactive-auth.html
#> The bigrquery package is using a cached token for ariel.balter@gmail.com.

bq_dataset_create(dataset)
#> <bq_dataset> elite-magpie-257717.test_dataset

conn = DBI::dbConnect(
  bigrquery::bigquery(),
  project = bq_test_project(),
  dataset = "test_dataset",
  KeyFilePath = "google_service_key.json",
  OAuthMechanism = 0
)


if (dbExistsTable(conn, "mtcars"))
{
  dbRemoveTable(conn, "mtcars")
}

dbWriteTable(conn, "mtcars", mtcars)

#######################################################


### Access BQ table
mtcars_tbl = tbl(conn, "mtcars")
class(mtcars_tbl)
#> [1] "tbl_BigQueryConnection" "tbl_dbi"                "tbl_sql"               
#> [4] "tbl_lazy"               "tbl"

### Create new virtual table
hp_gt_100_tbl = mtcars_tbl %>% filter(hp>100)
class(hp_gt_100_tbl)
#> [1] "tbl_BigQueryConnection" "tbl_dbi"                "tbl_sql"               
#> [4] "tbl_lazy"               "tbl"

### Write new table
dbWriteTable(conn, "hp_gt_100", hp_gt_100_tbl)
#> Error in (function (classes, fdef, mtable) : unable to find an inherited method for function 'dbWriteTable' for signature '"BigQueryConnection", "character", "tbl_BigQueryConnection"'

dbExecute(conn, "DROP TABLE mtcars")
#> [1] 0
dbExecute(conn, "DROP TABLE hp_gt_100")
#> Error: Job 'elite-magpie-257717.job_O8e7BtdfAnAb_8Vdtwybibgd7DpA.US' failed
#> x Not found: Table elite-magpie-257717:test_dataset.hp_gt_100 [notFound]

reprex package (v0.3.0) 于 2020 年 11 月 11 日创建

【问题讨论】:

    标签: r dplyr google-bigquery dbplyr bigrquery


    【解决方案1】:

    我接受 Simon S.A. 的回答。但是,我确实设法使用bigrquery 函数bq_project_query 找到了更直接的方法。

    library(DBI)
    library(dplyr, warn.conflicts = FALSE)
    library(bigrquery)
    
    bq_deauth()
    bq_auth(email="ariel.balter@gmail.com")
    
    
    ############  CREATE BQ TABLE TO ACCESS  #################
    
    dataset = bq_dataset("elite-magpie-257717", "test_dataset")
    
    if (bq_dataset_exists(dataset))
    {
      bq_dataset_delete(dataset, delete_contents = T)
    }
    bq_dataset_create(dataset)
    #> <bq_dataset> elite-magpie-257717.test_dataset
    
    conn = dbConnect(
      bigrquery::bigquery(),
      project = "elite-magpie-257717",
      dataset = "test_dataset",
      KeyFilePath = "google_service_key.json",
      OAuthMechanism = 0
    )
    
    dbWriteTable(conn, "mtcars", mtcars, overwrite=T)
    
    dbListTables(conn)
    #> [1] "mtcars"
    
    #######################################################
    
    
    ### Access BQ table
    mtcars_tbl = tbl(conn, "test_dataset.mtcars")
    class(mtcars_tbl)
    #> [1] "tbl_BigQueryConnection" "tbl_dbi"                "tbl_sql"               
    #> [4] "tbl_lazy"               "tbl"
    
    ### Create new virtual table
    hp_gt00_tbl = mtcars_tbl %>% filter(hp>100)
    class(hp_gt00_tbl)
    #> [1] "tbl_BigQueryConnection" "tbl_dbi"                "tbl_sql"               
    #> [4] "tbl_lazy"               "tbl"
    
    hp_gt00_tbl %>% dbplyr::sql_render()
    #> <SQL> SELECT *
    #> FROM `test_dataset.mtcars`
    #> WHERE (`hp` > 100.0)
    
    bq_project_query(
      x = dataset$project,
      query = hp_gt00_tbl %>% dbplyr::sql_render(),
      destination = bq_table(dataset, "hp_gt_00")
    )
    #> <bq_table> elite-magpie-257717.test_dataset.hp_gt_00
    
    bq_dataset_tables(dataset)
    #> [[1]]
    #> <bq_table> elite-magpie-257717.test_dataset.hp_gt_00
    #> 
    #> [[2]]
    #> <bq_table> elite-magpie-257717.test_dataset.mtcars
    
    bq_dataset_delete(dataset, delete_contents = T)
    

    reprex package (v0.3.0) 于 2020 年 11 月 15 日创建

    【讨论】:

      【解决方案2】:

      我认为您无法使用当前的方法通过 dbWriteTable 执行此操作。 dbWriteTable "将 [本地] 数据框写入、覆盖或附加到数据库表中" (source)。

      因此,一种选择是将这些数据收集到 R 中,然后他们使用 dbWriteTable 将其写回 SQL。但这可能效率低下。

      我推荐的方法是创建一个 bigquery INSERT INTO 语句并将其传递给 dbExecute。类似于以下内容:

      sql_query <- glue::glue("INSERT INTO {db}.{schema}.{tbl_name}\n",
                               dbplyr::sql_render(input_tbl))
      
      result <- dbExecute(db_connection, as.character(sql_query))
      

      sql_render 将获取当前虚拟表的定义并返回查询文本。 dbExecute 会将此命令传递给 bigquery 服务器以执行。

      请注意,我对 bigquery 的 INSERT INTO 语法不够熟悉,无法确保上述 sql_query 的语法是正确的,但我知道一般方法适用于我在 SQL 服务器中广泛使用 dbplyr 和 DBI。

      【讨论】:

      • 这绝对有效,在其他情况下可以放在我的后兜里。我设法通过适当的开关使用dplyrcopy_to 函数找到解决问题的方法。
      • 感谢@Simom.S.A @abalter 的解决方案,您愿意使用dplyrcopy_to 函数分享您的解决方案
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-11-07
      • 2020-06-16
      • 2023-03-19
      • 2015-12-22
      • 1970-01-01
      • 1970-01-01
      • 2022-06-20
      相关资源
      最近更新 更多