使用dm_add_pk为现有dm对象添加主键时动态取值异常求助
使用dm包的
dm_add_pk时,动态变量传参失效但字面量正常的问题 我在使用dm_add_pk为已创建的dm对象添加主键时遇到了一个诡异的问题:直接用字面量指定表名和主键列时正常工作,但用变量(比如循环中动态取值、或存在单独变量里的值)传递完全相同的内容时,要么报错要么静默失败,主键根本没创建。
我已经通过多种方式验证过变量值和字面量完全一致,但行为就是不一样。这是R的设计特性吗?有没有人遇到过类似情况?
最小复现代码
(注:conn是通过DBI::dbConnect和RPostgres创建的PostgreSQL连接)
import::from(dm, new_dm, copy_dm_to, dm_add_pk) import::from(purrr, map, set_names) DATA_MODELS <- list( "TableName" = list( "cols" = data.frame( run_id=character(), col_1=character(), col_2=numeric() ), "keys" = c("run_id", "col_2") ) ) tables_named_list <- map(DATA_MODELS, ~ set_names(.x, names(.x))) tables_to_migrate <- list() tablenames <- list() for (t in names(tables_named_list)) { tables_to_migrate <- append(tables_to_migrate, list(tables_named_list[[t]][["cols"]])) tablenames <- append(tablenames, t) } names(tables_to_migrate) <- tablenames data_model <- new_dm(tables_to_migrate) for (table in names(tables_to_migrate)) { # 这一行执行失败 dm_add_pk(data_model, table=!!table, columns=c(DATA_MODELS[[table]][["keys"]])) # 这一行能运行但静默失败,主键未创建 # dm_add_pk(data_model, table=!!table, columns=c("run_id", "col_2")) } # 下面第一行同样失败,第二行正常工作 # dm_add_pk(data_model, table=!!table, columns=c(DATA_MODELS[[table]][["keys"]])) # dm_add_pk(data_model, table=!!table, columns=c("run_id", "col_2"))
验证变量与字面量一致性的代码
c("run_id", "col_2") == c(DATA_MODELS[[table]][["keys"]]) typeof(c("run_id", "col_2")) == typeof(c(DATA_MODELS[[table]][["keys"]])) class(c("run_id", "col_2")) == class(c(DATA_MODELS[[table]][["keys"]])) compare(c("run_id", "col_2"), c(DATA_MODELS[[table]][["keys"]]))
环境信息
- dm:
1.0.3 - R:
4.2.2 - 数据库: PostgreSQL 14.6 (Debian 14.6-1.pgdg110+1)
- DBI:
Version: 1.1.3, Source: Repository, Repository: CRAN, Hash: b2866e62bab9378c3cc9476a1954226b - 系统: Linux 5.15.0-58-generic #64-Ubuntu SMP Thu Jan 5 11:43:13 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux
问题原因与解决方法
核心问题
- 非标准求值(NSE)特性:dm包的多数函数默认使用NSE简化语法,直接写列名无需引号。但当用变量传递字符向量时,必须用
all_of()显式告知函数:这是要使用的列名字符向量,而非待解析的符号名。 - dm对象不可变性:dm对象是不可变的,所有修改操作都会返回新对象,若不重新赋值,原对象不会有任何变化——这也是之前代码静默失败的关键原因。
修改后的代码
for (table in names(tables_to_migrate)) { # 用all_of()包裹变量传递的列名,同时重新赋值保存修改后的dm对象 data_model <- dm_add_pk(data_model, table = !!table, columns = all_of(DATA_MODELS[[table]][["keys"]])) }
内容的提问来源于stack exchange,提问作者oropo
相关产品推荐
相关产品推荐

