不使用 first() 的 Spark SQL vs Normal SQL 查询错误
Posted
技术标签:
【中文标题】不使用 first() 的 Spark SQL vs Normal SQL 查询错误【英文标题】:Spark SQL vs Normal SQL query error without using first() 【发布时间】:2020-11-21 14:21:54 【问题描述】:我试图在 Spark SQL 中运行一个简单的查询,但除非我使用 first(),否则它会抛出错误
此查询在 mysql 中正常工作
SELECT film.title,count(rental.rental_id) as total_rentals, film.rental_rate, count(rental.rental_id) * film.rental_rate as revenue
FROM rental
INNER JOIN inventory ON rental.inventory_id = inventory.inventory_id
INNER JOIN film ON inventory.film_id = film.film_id
GROUP BY film.title
ORDER BY 1
但 Spark SQL 不一样 我得到的错误是:
Exception in thread "main" org.apache.spark.sql.AnalysisException: expression 'film.`rental_rate`' is neither present in the group by, nor is it an aggregate function. Add to group by or wrap in first() (or first_value) if you don't care which value you get.;;
这样做实际上可以解决问题
SELECT film.title,count(rental.rental_id) as total_rentals, first(film.rental_rate), count(rental.rental_id) * first(film.rental_rate) as revenue
FROM rental
INNER JOIN inventory ON rental.inventory_id = inventory.inventory_id
INNER JOIN film ON inventory.film_id = film.film_id
GROUP BY film.title
ORDER BY 1
有人能解释一下为什么需要 Spark SQL 吗?
【问题讨论】:
【参考方案1】:SQL 中有一个共同要求,即group by
查询中的所有非聚合列都必须出现在group by
子句中。一些数据库理解功能依赖列的概念,并允许您将主键列仅放在 group by
子句中。
我猜title
不是film
的主键,所以你原来的查询不是有效的标准SQL。我怀疑您在 MySQL 中运行它,它(唉!)具有允许禁用标准要求的选项。
在支持group by
中的函数依赖的数据库中,您可以将查询分阶段为:
SELECT f.title, count(*) as total_rentals, f.rental_rate, count(*) * f.rental_rate as revenue
FROM rental r
INNER JOIN inventory i ON r.inventory_id = i.inventory_id
INNER JOIN film f ON i.film_id = f.film_id
GROUP BY f.film_id
ORDER BY 1
我认为 Spark 不会理解这一点,所以只需将所有需要的列添加到 group by
子句:
SELECT f.title, count(*) as total_rentals, f.rental_rate, count(*) * f.rental_rate as revenue
FROM rental r
INNER JOIN inventory i ON r.inventory_id = i.inventory_id
INNER JOIN film f ON i.film_id = f.film_id
GROUP BY f.film_id, f.title, f.rental_rate
ORDER BY 1
注意事项:
在group by
子句中包含film_id
仍然是一个好习惯;在现实生活中,两部不同的电影可能具有相同的标题和评分,您不想将它们组合在一起
count(r.rental_id)
可以简化为count(*)
(因为显然该列不能是null
表别名使查询更易于编写和阅读
【讨论】:
感谢您的快速反馈。那么对于 MySQL 等,它会在后台自动完成?【参考方案2】:我怀疑你想要:
SELECT f.title, COUNT(*) as total_rentals, f.rental_rate,
SUM(f.rental_rate) as revenue
FROM rental r JOIN
inventory i
ON r.inventory_id = i.inventory_id JOIN
film f
ON i.film_id = f.film_id
GROUP BY f.title, f.rental_rate
ORDER BY 1;
注意事项:
一般来说,GROUP BY
列应该是SELECT
中的未聚合列。在过去的几年里,这甚至在 MySQL 中是必需的(使用默认设置)。
您可以对rental_rate
列求和。无需计数和乘法。
表别名使查询更易于编写和阅读。
第一个 SQL 在 MySQL 中起作用是因为 MySQL 扩展了 SQL 语法以允许它。 SparkSQL(在这种情况下)正在做几乎所有其他数据库所做的事情。
【讨论】:
我又向codereview.stackexchange.com/questions/252458/… 发布了一个问题,您能解释一下区别吗? @戈登林诺夫以上是关于不使用 first() 的 Spark SQL vs Normal SQL 查询错误的主要内容,如果未能解决你的问题,请参考以下文章
Spark SQL 可以在 GROUP BY 聚合中使用 FIRST_VALUE 和 LAST_VALUE(但这不是标准的)
如何为 Spark SQL 中的posexplode 列提供别名?