在 Bigquery 中不使用行 number/window 函数获取最小值
Get minimum without using row number/window function in Bigquery
我有一个table如下图
我想做的是获得每个科目的最小值。虽然我可以用 row_number
函数来做到这一点,但我想用 groupby
和 min()
方法来做到这一点。但是没用。
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
我有一个table如下图
我想做的是获得每个科目的最小值。虽然我可以用 row_number
函数来做到这一点,但我想用 groupby
和 min()
方法来做到这一点。但是没用。
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