【问题标题】:Hive SQL Ranking With TiesHive SQL 排名与关系
【发布时间】:2025-12-12 04:10:01
【问题描述】:

如何在 Hive SQL 中重写下面的查询 我已经在 Oracle SQL 中尝试了以下内容,它可以工作,但需要在 Hive QL 中编写相同的代码

select * from sales order by unit_price fetch with ties

【问题讨论】:

    标签: sql oracle hive hiveql ranking-functions


    【解决方案1】:

    Oracle 的 ORDER BY .. FETCH NEXT N ROWS WITH TIRES 用于将返回的 top N(使用 ORDER BY)行数限制为 NEXT(FIRST)指定的数量。而使用轮胎意味着如果某些行具有相同的值顺序,除了指定的行数之外,它们也将被返回。

    Hive 没有 FETCH 功能。有LIMIT,不支持WITH TIRES。

    您可以使用分析的 dense_rank() 函数加上 WHERE 过滤器来实现类似的功能。例如,我们需要获取 5 个最低价格的销售,如果有相同价格的销售,也返回它们。 dense_rank 将为具有相同价格的行分配相同的排名。

    select * 
    from
    (
        select s.*, 
               dense_rank() over(order by unit_price) rnk --lowest unit_price first
                                                          --to get highest price, use order by unit_price DESC
         from sales s 
    ) 
    where rnk<=5  --If there are rows with the same rank, they all will be returned
    order by rnk
    

    【讨论】:

    • 我理解答案,即使它不正确。 dense_rank() 不像 with ties 那样做。
    【解决方案2】:

    用窗口函数来复制这是相当棘手的。 fetch with ties 返回到第 nth 行,然后返回具有相同值的所有行。所以,一种方法是:

    select s.*
    from sales *
    where s.unit_price <= (select s2.unit_price
                           from sales s2
                           order by unit_price 
                           limit 4, 1
                          );
    

    这并不准确,因为如果少于 5 行,它就不起作用。使用窗口函数的替代方法可以更轻松地解决此问题:

    select s.*
    from (select s.*,
                 max(case when seqnum = 5 then unit_price end) over () as unit_price_5
          from (select s.*,
                       row_number() over (order by unit_price) as seqnum
                from s
               ) s
         ) s
    where unit_price <= unit_price_5 or
          unit_price_5 is null;
    

    请注意,没有任何内置的窗口函数可以处理这种情况。例如,如果价格是:

    1
    1
    1
    1
    1
    1
    2
    

    那么row_number() 将只返回前5 个1s。 dense_rank()rank() 将返回所有行。

    【讨论】: