R语言如何实现基于OR条件的表连接 支持Base R与dplyr实现
解决方案
完全可以单步完成该逻辑的连接,以下分别给出dplyr、Base R的实现方法,也附sqldf的单步写法供参考:
前置处理:日期类型转换
首先建议把因子类型的日期转为标准Date类型,避免比较逻辑出错:
# 通用预处理代码 table_1$date_1 <- as.Date(table_1$date_1) table_2$date_2 <- as.Date(table_2$date_2) table_2$date_3 <- as.Date(table_2$date_3)
dplyr 实现(推荐)
使用dplyr 1.1.0及以上版本提供的join_by函数,可直接在连接条件中写OR逻辑:
library(dplyr) result <- left_join( x = table_1, y = table_2, join_by( # 直接写两个条件的OR关系 (id == id & between(date_1, date_2, date_3)) | (id2 == id2 & between(date_1, date_2, date_3)) ) ) %>% distinct() # 去重,和原逻辑的duplicated操作效果一致
Base R 实现
通过先做笛卡尔积、再过滤匹配行、最后补全无匹配行的逻辑实现:
# 生成两表的笛卡尔积 cross_join <- merge(table_1, table_2, by = NULL) # 过滤满足OR连接条件的行 matched <- cross_join[ (cross_join$id.x == cross_join$id.y & cross_join$date_1 >= cross_join$date_2 & cross_join$date_1 <= cross_join$date_3) | (cross_join$id2.x == cross_join$id2.y & cross_join$date_1 >= cross_join$date_2 & cross_join$date_1 <= cross_join$date_3), ] # 补全table_1中无匹配的行,实现左连接效果 unmatched <- table_1[!interaction(table_1[c("id", "id2", "date_1")]) %in% interaction(matched[c("id.x", "id2.x", "date_1")]), ] for (col in setdiff(colnames(table_2), colnames(table_1))) { unmatched[[col]] <- NA } # 合并结果并去重 result_base <- unique(rbind(matched, unmatched))
sqldf 单步实现
其实你原来用的sqldf也可以直接在ON子句中写OR逻辑,不需要分两次连接:
library(sqldf) result_sqldf <- sqldf(" select distinct a.*, b.* from table_1 a left join table_2 b on (a.id = b.id and a.date_1 between b.date_2 and b.date_3) or (a.id2 = b.id2 and a.date_1 between b.date_2 and b.date_3) ")
以上所有方法得到的结果和你原有的分两次连接再去重的结果完全一致。
内容的提问来源于stack exchange,提问作者stats_noob
相关产品推荐
相关产品推荐

