【问题标题】:r equivalent of sql update? [duplicate]r 相当于 sql 更新? [复制]
【发布时间】:2014-04-24 15:02:14
【问题描述】:

我环顾四周,找不到简单的答案。 我该如何做 SQL 中的更新表? 例如:

> df1 = data.frame(id=seq(1:3), v1=c("a", "b", NA))
> df1
  id   v1
1  1    a
2  2    b
3  3 <NA>
> df2 = data.frame(id=seq(1:3), v2=c("z", "y", "c"))
> df2
  id v2
1  1  z
2  2  y
3  3  c

如何在 v1 中使用 v2 中的值更新 df1,但仅在 id 匹配且 id > 2 时? 我查看了 data.table,但无法弄清楚 := 语法,并希望在基本 R 中有一些简单的东西?期望的输出是:

> df1
  id   v1
1  1    a
2  2    b
3  3    c

【问题讨论】:

    标签: sql r


    【解决方案1】:

    df1 中没有df2 中存在id 时,以及如果订单不同,更新后可以正常工作。只要只有一个 id 列,此方法就有效:

    df1 <- data.frame(id=seq(1:5), v1=c("a", "b", NA, NA, NA), stringsAsFactors=F)
    df2 <- data.frame(id=seq(1:3), v2=c("z", "y", "c"), stringsAsFactors=F)
    
    df1[df1$id > 2, -1] <- df2[df1$id[df1$id > 2], -1]
    df1
    

    生产:

      id   v1
    1  1    a
    2  2    b
    3  3    c
    4  4 <NA>
    5  5 <NA>
    

    这是一个简单的解决方案,只要两个数据帧具有相同的 id 集,它就可以工作:

    df1[df1$id > 2, ] <- df2[df1$id > 2, ]
    

    生产:

      id v1
    1  1  a
    2  2  b
    3  3  c
    

    重要的是,v1v2 需要是字符,所以在之前运行它,因为它们默认是 factor

    df1$v1 <- as.character(df1$v1)    
    df2$v2 <- as.character(df2$v2)
    

    如果您需要连接多个列,或者如果一个表中的 id 不全部存在于另一个表中,您可以使用 mergedata.table 在一个表上获取两个变量,然后构造新列通过将列与ifelse 组合在一起。

    【讨论】:

    • 啊,好的,两个dfs都有额外的列,每个id列都有额外的id。 ifelse 语法如何为每一行工作?没有更直接的方法吗?用sql就是这么简单..
    • 这样的? df1$v1[is.na(df1$v1)] = df1$v2[is.na(df1$v1)]
    • @Paul,请参阅更新。请注意,多个数据列不是问题。如果您有多个 id 列,这将停止工作。
    【解决方案2】:

    SQLite 可以通过 sqldf 在 sqlite 中使用更新:

    library(sqldf)
    
    sqldf(c("update df1 
             set v1 = (select v2 from df2 where df2.id = df1.id) 
             where id > 2", 
            "select * from df1"))
    

    给出:

      id v1
    1  1  a
    2  2  b
    3  3  c
    

    MySQL 这适用于 MySQL:

    library(RMySQL)
    library(sqldf)
    
    sqldf(c("update df1 
      left join df2 on (df1.id = df2.id and df1.id > 2)
      set df1.v1 = coalesce(df2.v2, df1.v1)",
      "select * from df1")
    )
    

    给予:

      id v1
    1  1  a
    2  2  b
    3  3  c
    

    base R 这也有效。前两行只是将 v1 和 v2 转换为字符,如果 v1 和 v2 已经是字符,则可以避免:

    df1c <- transform(df1, v1 = as.character(v1))
    df2c <- transform(df2, v2 = as.character(v2))
    transform(df1c, v1 = ifelse(id > 2, df2c[match(id, df2c$id), "v2"], v1))
    

    更新已合并 cmets 并添加了基础 R 解决方案。

    【讨论】:

    • 也许这接近于一个观点/理论问题.. 但是为什么 R 中没有一个很好的函数来执行我认为常见且必要的数据库(甚至数据框)操作? R 中有这么多很棒的函数可以做几乎所有其他事情,我想我只是有点惊讶这很复杂。
    • 谢谢你 - 我想我可能会走这条路.. 跟踪我想要匹配的内容似乎更简单,没有括号
    • @Grothendieck 感谢这个 sqlite 解决方案。我认为sql可以简化。设置部分:set v1 = (select v2 from df2 where df2.id = df1.id)。其中部分:where id &gt; 2.
    猜你喜欢
    • 2013-02-10
    • 2011-03-08
    • 1970-01-01
    • 1970-01-01
    • 2015-03-28
    • 1970-01-01
    • 2019-08-11
    • 2011-06-25
    • 1970-01-01
    相关资源
    最近更新 更多