在 SQL 中,为什么此 JOIN 返回键列两次?

in SQL, why is this JOIN returning the key column twice?

如果这是一个愚蠢的问题,我很抱歉,但我似乎无法理解它。我是 SQL 的新手,这种行为在 R 或 Pandas 或我习惯使用的其他东西中会很奇怪。

基本上,我在两个不同的数据库中有两个 table,它们有一个公共键 user_id。我想用

加入所有列
SELECT * FROM db1.first_table t1 
JOIN db2.second_table t2 
ON t1.user_id = t2.user_id

很好,很有效。除了有两个(相同的)列称为 user_id。这并不重要,除了我在 pyspark 中执行此操作并且当我尝试将连接的 table 导出到平面文件时,我收到一个错误,其中两列具有相同的名称。有解决方法,但我只是想知道是否有人可以解释为什么加入 returns both user_id 列。它似乎是一个内部连接,所以根据定义,列是相同的。为什么 return 两者都会?

作为附带问题,是否有避免这种行为的简单方法?

提前致谢!

SELECT * returns 查询的所有 table 中的所有列。这包括 user_id 列 - 一列来自 table A,一列来自 table B.

最佳做法是列出您希望明确返回的列名称,但缩短列表的另一个选项是:

SELECT TableA.*, 
       TableB.col1, 
       TableB.col2, 
       ...rest of B columns except user_id

这是因为您正在使用 Select *。当在 SELECT 之后只定义 * 时,它 return 来自两个 table 的所有列。您必须定义列名。始终定义要显示的列。你可以这样做:

SELECT t1.userid, t1.ColumnName1, t2.ColumnName2
FROM db1.first_table t1 
INNER JOIN db2.second_table t2 ON t1.user_id = t2.user_id

*有以下几种用法:

以下查询将 return 来自两个 table 的所有列:

SELECT *
FROM db1.first_table t1 
INNER JOIN db2.second_table t2 ON t1.user_id = t2.user_id

以下查询将 return 来自 first_table table:

的所有列
SELECT t1.*
FROM db1.first_table t1 
INNER JOIN db2.second_table t2 ON t1.user_id = t2.user_id

以下查询将 return 来自 Second_table table:

的所有列
SELECT t2.*
FROM db1.first_table t1 
INNER JOIN db2.second_table t2 ON t1.user_id = t2.user_id

此外,您可以通过这种方式从一个 table 中获取所有列并从其他 table 中获取某些列:

SELECT t1.*, t2.ColumnName
FROM db1.first_table t1 
INNER JOIN db2.second_table t2 ON t1.user_id = t2.user_id

您可以减少引用所需字段的字段数。

现在你有

  SELECT *

等于

  SELECT t1.*, t2.*

也许你想要

  SELECT t1.*, t2.field1, t2.field2 ...

好的,我找到了一种无需输入所有列名即可执行此操作的方法(正如我在评论中提到的,总共有 ~5k 列)。

这是 pyspark 特有的,但我只是将列名导出到 csv 并将它们加载并执行了以下操作:

with open("t1_cols.csv") as data_file:    
    t1_cols = data_file.read().split('\n')
with open("t2_cols.csv") as data_file:    
    t2_cols = data_file.read().split('\n')

sql = 'SELECT t1.user_id, t1.' + ', t1.'.join(t1_cols) + \
', t2.' + ', t2.'.join(t2_cols) + ' ' + \
'FROM db1.first_table t1 JOIN db2.second_table t2 ON t1.user_id = t2.user_id'

df = sqlContext.sql(sql)

有点讨厌,但它奏效了。

此外,我接受了第一个答案,因为以上所有答案在技术上都是正确的,而且这是第一个。感谢您的帮助!

所有这些答案(除了 OP 自己写的那个)似乎都假设我们在非常小的表上操作,我们可以在其中手动输入我们需要的每一列。

PySpark 中最简单的解决方案是使用 DataFrame 连接语法:

df = left_df.join(right_df, ["name"])

这不会复制该列并且表现得像 pandas 合并。如果没有特殊原因必须将其写为 sql 命令,我会推荐这个。将此与

对比
df = left_df.join(right_df, left.name == right.name) 

这将表现得像 SQL 加入并保留两列!

这也适用于 Scala 和 R,see here

另一个解决方案是将第二个目标列重命名为 "target_dataframe2",然后加入 sql,然后再次删除 "target_dataframe2"。

如果您只想打印 user_id 的一列,那么您应该使用带有 USING 关键字的内部联接。

当您将 USING 关键字与列名一起使用时,它会从两个表中过滤掉该公共列并仅显示一个。但是,当您将 ON 与条件 t1.user_id = t2.user_id 一起使用时,这只是在条件中使用了具有相同名称的列的巧合。

ON也用于比较两个表的不同列,所以它不会根据条件过滤掉列。所以,如果你想在加入后只显示一次公共列,那么你应该使用 USING 关键字。