【问题标题】:many to many join (same ID with different date)多对多加入(相同的 ID 不同的日期)
【发布时间】:2015-11-06 20:18:53
【问题描述】:

我正在使用 SQL 和 R 进行分析,我想加入如下所列的两个表:

表 1:

ID  date
a11 20150302
a11 20150302
a22 20150303
a22 20150304
a33 20150306
a44 20150306
a55 20150307
a66 20150308
a66 20150309
a66 20150310

表 2

ID  date
a11 20150303
a22 20150304
a22 20150305
a44 20150306
a66 20150308
a66 20150310

情况是这样的:客户接到电话(表 1),客户回电了解更多信息(表 2)

所以我想在分析中做的是:

  1. 只显示两个表中的 ID。
  2. 将表 2 日期与表 1 日期匹配:
    • 匹配最近的日期
    • 表 2 日期必须 >= 表 1 日期 (如结果“a66”中的示例 20150310 分配给 table1 日期 20150310,而 20150308 分配给 20150308,而不是 20150309)

结果:

ID  table1 date table2 date
a11 20150302    
a11 20150302    20150303
a22 20150303    20150304
a22 20150304    20150305
a44 20150306    20150306
a66 20150308    20150308
a66 20150309    
a66 20150310    20150310

对于这种多对多(但我不希望 n*m 作为结果,我想要 1 对 1)匹配/加入,是否有任何解决方案?将需要 R 或 SQL 中的解决方案。

谢谢

【问题讨论】:

  • 如果表 2 日期必须 >= 表 1 日期,为什么会有空格?在 table2 日期?
  • 为什么a11 有两行?您的 2.1 规则说与最接近的日期匹配。 null 不是最近的日期。
  • 你能更好地解释一下你的规则吗?不知道为什么 a11 20150302 同时有 null 和 20150303。还有为什么a66 20150309 null 而不是a66 20150309 20150310
  • 1.空格,因为对于某个 ID,表 1 有 3 条记录,而表 2 只有 2 条记录...就像打电话给客户 3 次,但客户只回电 2 次,所以空白表示客户没有回电的时间
  • 规则更像是,匹配是从表 2 一侧,表 2 将其日期匹配到表 1 中最接近的日期。而对于 a11,由于表 2 只有一个值,所以即使如果 a11 有两个 20150302,但我只想匹配其中一个,那么它会显示客户只调用一次......而不是两次

标签: sql r many-to-many match seq


【解决方案1】:
SELECT ID, Date1, Date2 FROM (
SELECT joined.ID,  joined.Date1, joined.Date2, ROW_NUMBER() OVER (PARTITION BY ID, Date1 ORDER BY Date2 ASC) AS RowNumber 
FROM(
SELECT t1.ID, t1.[Date] as Date1, CASE WHEN t2.[Date] >= t1.[Date] THEN t2.[Date] ELSE NULL END as [Date2] 
FROM Table1 t1
LEFT JOIN Table2 t2 ON t1.ID = t2.ID) as joined 
WHERE joined.Date2 IS NOT NULL
) partitioned
WHERE RowNumber = 1

加入ID 上的两个表并删除Table 2 中不在Table 1 中的行。然后使用ROW_NUMBER() OVER (PARTITION BY ID, Date1 ORDER BY Date2 ASC) 匹配WHERE RowNumber = 1 子句找到的最接近的日期。

产生与您列出的条件一致的输出:

+-----+----------+----------+
| ID  |  Date1   |  Date2   |
+-----+----------+----------+
| a11 | 20150302 | 20150303 |
| a22 | 20150303 | 20150304 |
| a22 | 20150304 | 20150304 |
| a44 | 20150306 | 20150306 |
| a66 | 20150308 | 20150308 |
| a66 | 20150309 | 20150310 |
| a66 | 20150310 | 20150310 |
+-----+----------+----------+

【讨论】:

  • 感谢您的回答,但它不会使输出:a66 的第一行变为 20150308 与 20150308 和 20150310 配对吗?在table2日期列上应该只有20150308
  • @KarlTian 编辑了我的答案,它符合您的条件。但是,您问题中的结果集与这些条件不一致。
  • 看起来很不错,谢谢@Markmanguy。还有一个问题,为什么在你的输出中,date2 列中,a22 的结果不是 20150304 和 20150305,而是 两个 20150304
  • @KarlTian 因为与20150304 最接近的日期是20150304,而不是20150305
【解决方案2】:

这并不能解决问题,但很接近,也许会给你一个想法

SqlFiddleDemo

With t_left as (
    SELECT *, row_number() over (partition by "ID" order by date desc ) as rn
    FROM Table1 T
    WHERE EXISTS (SELECT 1 FROM Table2 P WHERE T."ID" = P."ID")
),
t_right as (
    SELECT *, row_number() over (partition by "ID" order by date desc) as rn
    FROM Table2
) 
SELECT t_left."ID", t_left."date", t_right."date"
FROM t_left
LEFT JOIN t_right
       on t_left.rn = t_right.rn
      and t_left."ID" = t_right."ID"
ORDER BY t_left."ID", t_left."date"

输出

|  ID |     date |     date |
|-----|----------|----------|
| a11 | 20150302 | 20150303 |
| a11 | 20150302 |   (null) |
| a22 | 20150303 | 20150304 |
| a22 | 20150304 | 20150305 |
| a44 | 20150306 | 20150306 |
| a66 | 20150308 |   (null) |
| a66 | 20150309 | 20150308 |
| a66 | 20150310 | 20150310 |

【讨论】:

  • 谢谢!@Juan Carlos Oropeza
【解决方案3】:

我得到与 R 中的 markmanguy 相同的结果,dplyr。对于 a22,20150304 初始调用最接近的回调是 20150304,而不是 20150305。您需要一个时间组件来区分这一点。

library(dplyr)
inner_join(table1,table2,"ID")%>%
group_by(ID,date1)%>%
filter(date1<=date2)%>%
filter(row_number() == 1)

>
Source: local data frame [7 x 3]
Groups: ID, date1 [7]

     ID    date1    date2
  (chr)    (int)    (int)
1   a11 20150302 20150303
2   a22 20150303 20150304
3   a22 20150304 20150304
4   a44 20150306 20150306
5   a66 20150308 20150308
6   a66 20150309 20150310
7   a66 20150310 20150310

数据

table1 <-read.table(text="ID  date1
a11 20150302
a11 20150302
a22 20150303
a22 20150304
a33 20150306
a44 20150306
a55 20150307
a66 20150308
a66 20150309
a66 20150310", header=T,stringsAsFactors =F)
table2 <-read.table(text="ID  date2
a11 20150303
a22 20150304
a22 20150305
a44 20150306
a66 20150308
a66 20150310", header=T,stringsAsFactors =F)

【讨论】:

    猜你喜欢
    • 2019-12-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-10
    • 1970-01-01
    • 2021-06-06
    • 1970-01-01
    相关资源
    最近更新 更多