考虑下表
person_details
,这将是我的输入
id | 名字 | 信任名称 | 年龄 | 年龄信任 |
---|---|---|---|---|
1 | 约翰·多伊 | 90 | 空 | 空 |
1 | 约翰 D. | 50 | 25 | 90 |
1 | 空 | 0 | 二十几岁 | 50 |
这里
null
代表实际的空值。 trust*
列可以具有 10 倍数和 null
的整数值,其中我使用 COALESCE
函数将此类空值替换为 0
。
我现在想形成一个主行,其中
id
是我表中的主键列。这是由特定列的信任值驱动的,这里具有最高值的trust_on_name
将驱动我将选择的name
的值,因此我将选择突出显示的值并形成最后一行,如下所示我的输出:
id | 名字 | 年龄 |
---|---|---|
1 | 约翰·多伊 | 25 |
为此,我尝试使用以下看似麻烦且不平凡的逻辑:
WITH cte_name AS (
SELECT id,
`name` AS name,
trust_on_name,
null as `age`,
trust_on_age
FROM person_details
QUALIFY trust_on_name = MAX(trust_on_name) OVER (PARTITION BY id)
),
cte_age AS (
SELECT id,
null as `name`,
trust_on_name,
age,
trust_on_age
FROM person_details
QUALIFY trust_on_age = MAX(trust_on_age) OVER (PARTITION BY id)
)
SELECT
A.id,
A.name,
B.age
FROM cte_name A
INNER JOIN cte_age B
ON A.id = B.id
WHERE A.trust_on_name > COALESCE(B.trust_on_name, 0) AND B.trust_on_age > COALESCE(A.trust_on_age, 0)
现在,假设我们在表中有很多这样的列(即
<column>
,<trust_on_column>
对),是否有更好的替代方法可以迭代地执行此操作,并且使用这种方法,我将不得不为每个(<column>
)创建如此多的ctes
、<trust_on_column>
)组合并进行连接以识别作为整体可信的一条记录!?
我使用 Spark-SQL 和 Databricks 来运行和执行此逻辑。
您可以使用 group by /collect_list 以不同的方式执行此操作(分组然后查找):
import sparkSession.implicits._
val df = Seq(
("1", "John Doe", "90", null, null),
("1", "john D.", "50", "25", "90"),
("1", null, "0", "twenties", "50")
).toDF("id","name","trust_on_name","age","trust_on_age")
df.createOrReplaceTempView("person_details")
sparkSession.sql(
"""
select id, element_at(name, cast(array_position(trust_on_name, array_max(trust_on_name)) as int)) name,
element_at(age, cast(array_position(trust_on_age, array_max(trust_on_age)) as int)) age
from (
select id, collect_list(name) name,
collect_list(trust_on_name) trust_on_name,
collect_list(age) age,
collect_list(trust_on_age) trust_on_age
from person_details
group by id
distribute by id
)
"""
).show
需要进行强制转换,因为 array_position 返回 bigint 而 element_at 只接受 int。应适当选择分布方式,但如果行全部位于单个分区上,甚至在洗牌后也应保持一致。