You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

问题原因与解决方法

核心问题

  1. 非标准求值(NSE)特性:dm包的多数函数默认使用NSE简化语法,直接写列名无需引号。但当用变量传递字符向量时,必须用all_of()显式告知函数:这是要使用的列名字符向量,而非待解析的符号名。
  2. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 14:35:27