Получить минимум без использования номера строки / оконной функции в Bigquery - PullRequest
0 голосов
/ 28 сентября 2019

У меня есть таблица, как показано ниже

enter image description here

Что я хотел бы сделать, это получить минимум каждого предмета.Хотя я могу сделать это с помощью функции 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) достаточно, чтобы сгруппировать элементы вместе.Они помогут дифференцировать группу.Но почему я не могу использовать другие столбцы в предложении выбора.Если я использую другие столбцы, я могу не получить ожидаемый результат, потому что time_1 имеет другие значения.

Я ожидаю, что мой вывод будет таким, как показано ниже

enter image description here

Ответы [ 4 ]

2 голосов
/ 28 сентября 2019

В 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;
1 голос
/ 29 сентября 2019

Немного опоздал на вечеринку, но вот подход на основе 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
1 голос
/ 28 сентября 2019

Ниже для 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 неэффективно и во многих случаях приводит к ошибке превышения ресурсов.

Примечание: самостоятельное объединение - также очень неэффективный способ достижения вашей цели

1 голос
/ 28 сентября 2019

Вы ищете что-то вроде ниже-

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

Если вам не требуется выбирать значение столбца 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. 
...