存在匹配时排除不匹配行的 SQL 多对多连接

Posted

技术标签:

【中文标题】存在匹配时排除不匹配行的 SQL 多对多连接【英文标题】:SQL many to many join that excludes mismatching rows when a match exists 【发布时间】:2020-03-19 21:30:20 【问题描述】:

我有两个表,每刻钟都有数据。每一刻钟可以有多个观察值。我想要做的是将这些表连接在一起,并让所有观察结果匹配的行和观察结果不匹配的行在匹配时不显示不匹配。

例如:

表 A:

+-----+----------------+---------------+
| key |      qhr       | observation_A |
+-----+----------------+---------------+
|   1 | 1/1/2020 10:00 | A             |
|   1 | 1/1/2020 10:00 | B             |
|   1 | 1/1/2020 10:15 | A             |
|   1 | 1/1/2020 10:15 | B             |
|   1 | 1/1/2020 10:30 | B             |
|   1 | 1/1/2020 10:45 | A             |
|   1 | 1/1/2020 11:00 | B             |
|   1 | 1/1/2020 11:00 | C             |
|   1 | 1/1/2020 11:15 | C             |
|   2 | 1/1/2020 10:00 | C             |
|   2 | 1/1/2020 10:00 | B             |
|   2 | 1/1/2020 10:15 | A             |
|   2 | 1/1/2020 10:15 | C             |
|   2 | 1/1/2020 10:30 | A             |
|   2 | 1/1/2020 10:45 | C             |
|   2 | 1/1/2020 11:00 | A             |
|   2 | 1/1/2020 11:00 | C             |
|   2 | 1/1/2020 11:15 | B             |
+-----+----------------+---------------+

表 B:

+-----+----------------+---------------+
| key |      qhr       | observation_B |
+-----+----------------+---------------+
|   1 | 1/1/2020 10:00 | A             |
|   1 | 1/1/2020 10:00 | B             |
|   1 | 1/1/2020 10:15 | A             |
|   1 | 1/1/2020 10:15 | C             |
|   1 | 1/1/2020 10:30 | B             |
|   1 | 1/1/2020 10:45 | A             |
|   1 | 1/1/2020 11:00 | A             |
|   1 | 1/1/2020 11:00 | C             |
|   1 | 1/1/2020 11:15 | C             |
|   2 | 1/1/2020 10:00 | C             |
|   2 | 1/1/2020 10:00 | B             |
|   2 | 1/1/2020 10:15 | A             |
|   2 | 1/1/2020 10:15 | C             |
|   2 | 1/1/2020 10:30 | B             |
|   2 | 1/1/2020 10:45 | C             |
|   2 | 1/1/2020 11:00 | A             |
|   2 | 1/1/2020 11:15 | A             |
+-----+----------------+---------------+

预期输出:

+-----+----------------+---------------+---------------+-------+
| key |      qhr       | observation_A | observation_B | MATCH |
+-----+----------------+---------------+---------------+-------+
|   1 | 1/1/2020 10:00 | A             | A             | Y     |
|   1 | 1/1/2020 10:00 | B             | B             | Y     |
|   1 | 1/1/2020 10:15 | A             | A             | Y     |
|   1 | 1/1/2020 10:15 | B             | C             | N     |
|   1 | 1/1/2020 10:30 | B             | B             | Y     |
|   1 | 1/1/2020 10:45 | A             | A             | Y     |
|   1 | 1/1/2020 11:00 | B             | A             | N     |
|   1 | 1/1/2020 11:00 | C             | C             | Y     |
|   1 | 1/1/2020 11:15 | C             | C             | Y     |
|   2 | 1/1/2020 10:00 | C             | C             | Y     |
|   2 | 1/1/2020 10:00 | B             | B             | Y     |
|   2 | 1/1/2020 10:15 | A             | A             | Y     |
|   2 | 1/1/2020 10:15 | C             | C             | Y     |
|   2 | 1/1/2020 10:30 | A             | B             | N     |
|   2 | 1/1/2020 10:45 | C             | C             | Y     |
|   2 | 1/1/2020 11:00 | A             | A             | Y     |
|   2 | 1/1/2020 11:00 | C             |               | N     |
|   2 | 1/1/2020 11:15 | B             | A             | N     |
+-----+----------------+---------------+---------------+-------+

我尝试使用完全外连接(在键和 qhr 上连接)来包含观察结果不匹配的时间,但是当我这样做时,即使存在如下匹配,我也会获得每个组合潜力:

+-----+----------------+---------------+---------------+-------+
| key |      qhr       | observation_A | observation_B | MATCH |
+-----+----------------+---------------+---------------+-------+
|   1 | 1/1/2020 10:00 | A             | B             | N     |
|   1 | 1/1/2020 10:00 | A             | A             | Y     |
|   1 | 1/1/2020 10:00 | B             | B             | Y     |
|   1 | 1/1/2020 10:00 | B             | A             | N     |
+-----+----------------+---------------+---------------+-------+

我正在尝试找出一种方法来包含任何合法的不匹配但排除第 1 行和第 4 行,因为 A 和 B 实际匹配。

我在 spark 中工作,所以我可以使用 spark SQL 或 pyspark 数据帧来解决这个问题,甚至可能是 pandas。任何建议将不胜感激。

【问题讨论】:

我们在哪些列上绑定两个 dfs? 假设您有相同数量的观察,您可以为两个数据集创建一个monotonicallyincreasingid 并加入它们。 谢谢,但不,我们不能假设相同的观察结果。 【参考方案1】:

我不太明白您希望我们在加入两个数据框时将什么用作连接点。希望我读得好。我绑定了钥匙和qhr。如果不对就大声喊出来。你会得到帮助的。我的脚步; 将日期强制转换为日期时间,提取分钟并将其转换回对象类型

df4['qhrminute']=pd.to_datetime(df4['qhr']).dt.minute.astype('object')
df1['qhrminute']=pd.to_datetime(df1['qhr']).dt.minute.astype('object')

对 key 和 qhrminute 列执行外连接。与内部、左侧等相比,外部联接保留所有联接数据帧属性的所有值

merged_df = df4.merge(df1, how = 'outer', on = ['key', 'qhrminute'], suffixes=('_A', '_B'))

使用 np.where 检查和属性条件

merged_df['Match']= np.where(merged_df['obs_A'] == merged_df['obs_B'], 'Y', 'N')

删除不需要的列

merged_df.drop(columns=['qhr_A','qhrminute'], inplace=True)
merged_df.rename('qhr_B':'qhr', axis=1, inplace=True)
merged_df

组合 obs_Aobs_B 中的字符串,按字母顺序对它们进行排序,并将重复项放在组合的排序列和 qhr 上。

  merged_df["com"] = merged_df["obs_A"] + merged_df["obs_B"]
   merged_df['com1'] = merged_df['com'].apply(lambda x: ' '.join(sorted(x.split()))).sort_values( ascending=True)
merged_df.drop_duplicates(['qhr','com1'],keep= 'last')

【讨论】:

谢谢你,但我相信这仍然会产生不希望的输出。我试图避免外部连接将创建的第 4 个表中的示例。 在我最新的编辑中查看一个令人费解的补充,看看它是否有效;

以上是关于存在匹配时排除不匹配行的 SQL 多对多连接的主要内容,如果未能解决你的问题,请参考以下文章

sql 多对多查询结果仅当仅匹配且完全匹配数组中的所有项目时

SQL多对多,如何检查多行的条件

Mysql连接查询匹配所有标签的多个“标签”(多对多关系)?

从多对多连接表中检索行的 HQL 查询

hibernate关联关系(多对多)

多对多关系的查询集按列表中的匹配数排序