在 Bigquery 中不使用行 number/window 函数获取最小值

Get minimum without using row number/window function in Bigquery

我有一个table如下图

我想做的是获得每个科目的最小值。虽然我可以用 row_number 函数来做到这一点,但我想用 groupbymin() 方法来做到这一点。但是没用。

row_number 方法 - 工作正常

SELECT * FROM (select subject_id,value,id,min_time,max_time,time_1,
row_number() OVER (PARTITION BY subject_id ORDER BY value) AS rank
from table A) WHERE RANK = 1

min() 方法 - 不起作用

select subject_id,id,min_time,max_time,time_1,min(value) from table A
GROUP BY SUBJECT_ID,id

如您所见,仅 (subject_id and id) 两列就足以将项目组合在一起。他们将有助于区分群体。但是为什么我不能使用 select 子句中的其他列。如果我使用其他列,我可能无法获得预期的输出,因为 time_1 具有不同的值。

我希望我的输出如下所示

你在找下面这样的东西吗-

SELECT 
A.subject_id,
A.id,
A.min_time,
A.max_time,
A.time_1,
A.value 
FROM table A
INNER JOIN(
    SELECT subject_id, MIN(value) Value
    FROM table
    GROUP BY subject_id
) B ON A.subject_id = B.subject_id
AND A.Value = B.Value

如果您不需要 select Time_1 列的值,则以下查询将起作用(正如我所见,min_time 和 max_time 列中的值相同对于同一组)-

SELECT 
A.subject_id,A.id,A.min_time,A.max_time,
--A.time_1,
MIN(A.value) 
FROM table A
GROUP BY 
A.subject_id,A.id,A.min_time,A.max_time

最后,最好的方法是在时间列上应用类似 CAST(Time_1 AS DATE) 的方法。这将只考虑日期部分而不考虑时间部分。查询将是

SELECT 
A.subject_id,A.id,A.min_time,A.max_time,
CAST(A.time_1 AS DATE) Time_1,
MIN(A.value) 
FROM table A
GROUP BY 
A.subject_id,A.id,A.min_time,A.max_time,
CAST(A.time_1 AS DATE) 
-- Make sure the syntax of CAST AS DATE 
-- in BigQuery is as I written here or bit different. 

在 BigQuery 中,您可以为此使用聚合:

SELECT ARRAY_AGG(a ORDER BY value LIMIT 1)[SAFE_OFFSET(1)].*
FROM table A
GROUP BY SUBJECT_ID;

这使用 ARRAY_AGG() 聚合每条记录(参数列表中的 a)。 ARRAY_AGG() 允许您对结果进行排序(按 value)并限制数组的大小。后者对性能很重要。

连接数组后,您需要第一个元素。 .*a 引用的记录转换为组件列。

我不确定您为什么不想使用 ROW_NUMBER()。如果问题是挥之不去的 rank 列,您可以轻松将其删除:

SELECT a.* EXCEPT (rank)
FROM (SELECT a.*,
             ROW_NUMBER() OVER (PARTITION BY subject_id ORDER BY value) AS rank
      FROM A
     ) a
WHERE RANK = 1;

以下适用于 BigQuery Standard SQL,对于您问题中的此类情况,这是最有效的方法

#standardSQL
SELECT AS VALUE ARRAY_AGG(t ORDER BY value LIMIT 1)[OFFSET(0)]
FROM `project.dataset.table` t
GROUP BY subject_id   

使用ROW_NUMBER效率不高,在许多情况下会导致资源超出错误。

注意:自加入也是实现您的 objective

的非常无效的方法

聚会有点晚了,但这里有一个基于 cte 的方法,对我来说很有意义:

with mins as (
   select subject_id, id, min(value) as min_value
   from table
   group by subject_id, id
)
select distinct t.subject_id, t.id, t.time_1, t.min_time, t.max_time, m.min_value
from table t
join mins m on m.subject_id = t.subject_id and m.id = t.id