Hive / SQL - 左加入回退
Hive / SQL - Left join with fallback
在 Apache Hive 中,我必须 tables 我想左连接保留左侧数据中的所有数据并尽可能从右侧添加数据 table。
为此,我使用了两个连接,因为连接基于两个字段(material_id 和 location_id)。
这适用于两个传统的左连接:
SELECT
a.*,
b.*
FROM a
INNER JOIN (some more complex select) b
ON a.material_id=b.material_id
AND a.location_id=b.location_id;
对于 location_id 数据库只包含两个不同的值,比如 1 和 2。
我们现在有需求,如果没有"perfect match",就只能拼接material_id,没有material_id和[=37的正确组合=](例如 material_id=100 和 location_id=1)对于 b-table 中的 location_id 的连接,连接应该 "default" 或 "fallback" 到 location_id 的其他可能值,例如material_id=001 和 location_id=2,反之亦然。这应该只适用于 location_id.
我们已经用 CASE 等调查了所有可能的答案,但没有定论。像
这样的设置
...
ON a.material_id=b.material_id AND a.location_id=
CASE WHEN a.location_id = b.location_id THEN b.location_id ELSE ...;
我们尝试过或没有弄清楚在 Hive 查询语言中到底是怎么做的。
感谢您的帮助!也许有人有一个聪明的主意。
这是一些示例数据:
Table a
| material_id | location_id | other_column_a |
| 100 | 1 | 45 |
| 101 | 1 | 45 |
| 103 | 1 | 45 |
| 103 | 2 | 45 |
Table b
| material_id | location_id | other_column_b |
| 100 | 1 | 66 |
| 102 | 1 | 76 |
| 103 | 2 | 88 |
Left - Join Table
| material_id | location_id | other_column_a | other_column_b
| 100 | 1 | 45 | 66
| 101 | 1 | 45 | NULL (mat. not in b)
| 103 | 1 | 45 | DEFAULT TO where location_id=2 (88)
| 103 | 2 | 45 | 88
PS:如前所述,here存在等在子查询ON中不起作用。
解决方案是在没有 a.location_id = b.location_id
的情况下进行左连接,并按优先顺序对所有行进行编号。然后按 row_number 过滤。在下面的代码中,连接将首先复制行,因为将连接所有匹配的 material_id,然后 row_number()
函数会将 1 分配给 a.location_id = b.location_id
的行,将 2 分配给 a.location_id <> b.location_id
的行如果还存在 a.location_id = b.location_id
行,如果不存在则为 1。 b.location_id
添加到 row_number() 函数中的 order by
,因此如果没有完全匹配,它将 "prefer" 具有较低 b.location_id
的行。我希望你已经明白了。
select * from
(
SELECT
a.*,
b.*,
row_number() over(partition by material_id
order by CASE WHEN a.location_id = b.location_id THEN 1 ELSE 2 END, b.location_id ) as rn
FROM a
LEFT JOIN (some more complex select) b
ON a.material_id=b.material_id
)s
where rn=1
;
也许这对以后的人有帮助:
我们还想出了一个不同的方法。
首先,我们创建另一个 table 来计算 table b 基于所有 (!) 位置的 material_id 的平均值。
其次,在连接 table 中我们创建三列:
c1 - material_id 和 location_id 匹配的值(table a 与 table b 的左连接的结果)。如果没有完全匹配,则此列为空。
c2 - 来自 table 的值,我们从平均值(后备)table 中写入数字 material_id(无论位置如何)
c3 - "actual value" 列,我们在其中使用 case 语句来确定第 1 列何时为 NULL(material 和位置不存在完美匹配),然后我们使用来自的值第 2 列(material 所有其他位置的平均值)用于进一步计算。
在 Apache Hive 中,我必须 tables 我想左连接保留左侧数据中的所有数据并尽可能从右侧添加数据 table。 为此,我使用了两个连接,因为连接基于两个字段(material_id 和 location_id)。 这适用于两个传统的左连接:
SELECT
a.*,
b.*
FROM a
INNER JOIN (some more complex select) b
ON a.material_id=b.material_id
AND a.location_id=b.location_id;
对于 location_id 数据库只包含两个不同的值,比如 1 和 2。
我们现在有需求,如果没有"perfect match",就只能拼接material_id,没有material_id和[=37的正确组合=](例如 material_id=100 和 location_id=1)对于 b-table 中的 location_id 的连接,连接应该 "default" 或 "fallback" 到 location_id 的其他可能值,例如material_id=001 和 location_id=2,反之亦然。这应该只适用于 location_id.
我们已经用 CASE 等调查了所有可能的答案,但没有定论。像
这样的设置...
ON a.material_id=b.material_id AND a.location_id=
CASE WHEN a.location_id = b.location_id THEN b.location_id ELSE ...;
我们尝试过或没有弄清楚在 Hive 查询语言中到底是怎么做的。
感谢您的帮助!也许有人有一个聪明的主意。
这是一些示例数据:
Table a
| material_id | location_id | other_column_a |
| 100 | 1 | 45 |
| 101 | 1 | 45 |
| 103 | 1 | 45 |
| 103 | 2 | 45 |
Table b
| material_id | location_id | other_column_b |
| 100 | 1 | 66 |
| 102 | 1 | 76 |
| 103 | 2 | 88 |
Left - Join Table
| material_id | location_id | other_column_a | other_column_b
| 100 | 1 | 45 | 66
| 101 | 1 | 45 | NULL (mat. not in b)
| 103 | 1 | 45 | DEFAULT TO where location_id=2 (88)
| 103 | 2 | 45 | 88
PS:如前所述,here存在等在子查询ON中不起作用。
解决方案是在没有 a.location_id = b.location_id
的情况下进行左连接,并按优先顺序对所有行进行编号。然后按 row_number 过滤。在下面的代码中,连接将首先复制行,因为将连接所有匹配的 material_id,然后 row_number()
函数会将 1 分配给 a.location_id = b.location_id
的行,将 2 分配给 a.location_id <> b.location_id
的行如果还存在 a.location_id = b.location_id
行,如果不存在则为 1。 b.location_id
添加到 row_number() 函数中的 order by
,因此如果没有完全匹配,它将 "prefer" 具有较低 b.location_id
的行。我希望你已经明白了。
select * from
(
SELECT
a.*,
b.*,
row_number() over(partition by material_id
order by CASE WHEN a.location_id = b.location_id THEN 1 ELSE 2 END, b.location_id ) as rn
FROM a
LEFT JOIN (some more complex select) b
ON a.material_id=b.material_id
)s
where rn=1
;
也许这对以后的人有帮助:
我们还想出了一个不同的方法。
首先,我们创建另一个 table 来计算 table b 基于所有 (!) 位置的 material_id 的平均值。
其次,在连接 table 中我们创建三列: c1 - material_id 和 location_id 匹配的值(table a 与 table b 的左连接的结果)。如果没有完全匹配,则此列为空。
c2 - 来自 table 的值,我们从平均值(后备)table 中写入数字 material_id(无论位置如何)
c3 - "actual value" 列,我们在其中使用 case 语句来确定第 1 列何时为 NULL(material 和位置不存在完美匹配),然后我们使用来自的值第 2 列(material 所有其他位置的平均值)用于进一步计算。