Получение лучших результатов в одном запросе в bigquery - PullRequest
0 голосов
/ 27 февраля 2019

Предположим, у меня есть следующие два поля:

`name`     `age`
"tom"      20
"tom"      20
"brad"     10
"steve"    14
"alex"     13
"alex"     11

Я хочу заполнить панель фильтров на моей странице, которая дает максимальное количество для каждого поля.Например, это выглядело бы так:

name (top 2)
----------------
Alex (2)
Tom (2)

age (top 2)
----------------
20 (2)
10 (1)

Обычно я делал бы это с двумя запросами:

SELECT name, count(*) FROM mytable GROUP BY name ORDER BY count(*) DESC LIMIT 2;
SELECT age, count(*) FROM mytable GROUP BY age ORDER BY count(*) DESC LIMIT 2

Однако буквально могут быть сотни столбцов, поэтому я не хочуделать сотни запросов только для загрузки панели «Фильтры».Есть ли способ сделать вышеуказанное в одном запросе?Это должны быть точные результаты, поэтому он не может использовать что-то вроде APPROX_TOP_COUNT (если вы не можете указать точность 100%).

Как бы я построил вышеуказанный запрос?

Возможно,следующий запрос будет работать, но как я могу гарантировать, что результаты и подсчеты будут точными?

select APPROX_TOP_COUNT(name, 2), APPROX_TOP_COUNT(age, 2) from `mytable`

Мне нужна точная причина, потому что здесь могут быть финансовые данные, и, например, мне нужно датьточное количество «проданных единиц» или что-то подобное в боковой панели.

1 Ответ

0 голосов
/ 01 марта 2019

Ниже для BigQuery Standard SQL

#standardSQL
SELECT
  ARRAY(SELECT REGEXP_REPLACE(name, r'\(0*', '(') FROM t.names name ORDER BY name DESC) names,
  ARRAY(SELECT REGEXP_REPLACE(age, r'\(0*', '(') FROM t.ages age ORDER BY age DESC) ages
FROM (
  SELECT 
    ARRAY_AGG(DISTINCT name ORDER BY name DESC LIMIT 2) names,
    ARRAY_AGG(DISTINCT age ORDER BY age DESC LIMIT 2) ages
  FROM (
    SELECT 
      CONCAT('(', SUBSTR(CONCAT('00000', CAST(COUNT(1) OVER(PARTITION BY name) AS STRING)), -5), ') ', name) name,
      CONCAT('(', SUBSTR(CONCAT('00000', CAST(COUNT(1) OVER(PARTITION BY age) AS STRING)), -5), ') ', CAST(age AS STRING)) age
    FROM `project.dataset.table`
  )
) t

Вы можете протестировать, поиграть с выше, используя примеры данных из вашего вопроса, как в примере ниже

#standardSQL
WITH `project.dataset.table` AS (
  SELECT 'tom' name, 20 age UNION ALL
  SELECT 'tom', 20 UNION ALL
  SELECT 'brad', 10 UNION ALL
  SELECT 'steve', 14 UNION ALL
  SELECT 'alex', 13 UNION ALL
  SELECT 'alex', 11 
)
SELECT
  ARRAY(SELECT REGEXP_REPLACE(name, r'\(0*', '(') FROM t.names name ORDER BY name DESC) names,
  ARRAY(SELECT REGEXP_REPLACE(age, r'\(0*', '(') FROM t.ages age ORDER BY age DESC) ages
FROM (
  SELECT 
    ARRAY_AGG(DISTINCT name ORDER BY name DESC LIMIT 2) names,
    ARRAY_AGG(DISTINCT age ORDER BY age DESC LIMIT 2) ages
  FROM (
    SELECT 
      CONCAT('(', SUBSTR(CONCAT('00000', CAST(COUNT(1) OVER(PARTITION BY name) AS STRING)), -5), ') ', name) name,
      CONCAT('(', SUBSTR(CONCAT('00000', CAST(COUNT(1) OVER(PARTITION BY age) AS STRING)), -5), ') ', CAST(age AS STRING)) age
    FROM `project.dataset.table`
  )
) t

с результатом

Row     names       ages     
1       (2) tom     (2) 20   
        (2) alex    (1) 14   

Обновление для I'd like to have it as an array (exactly as it would be in select APPROX_TOP_COUNT(name, 2), APPROX_TOP_COUNT(age, 2) from mytable)

См. Ниже - изменены только две строки во внешнем SELECT

#standardSQL
WITH `project.dataset.table` AS (
  SELECT 'tom' name, 20 age UNION ALL
  SELECT 'tom', 20 UNION ALL
  SELECT 'brad', 10 UNION ALL
  SELECT 'steve', 14 UNION ALL
  SELECT 'alex', 13 UNION ALL
  SELECT 'alex', 11 
)
SELECT
  ARRAY(SELECT STRUCT(REGEXP_EXTRACT(name, r'\(\d*\) (.*)') AS value, CAST(REGEXP_EXTRACT(name, r'\((\d*)\)') AS INT64) AS `count`) FROM t.names name ORDER BY name DESC) names,
  ARRAY(SELECT STRUCT(REGEXP_EXTRACT(age, r'\(\d*\) (.*)') AS value, CAST(REGEXP_EXTRACT(age, r'\((\d*)\)') AS INT64) AS `count`) FROM t.ages age ORDER BY age DESC) ages
FROM (
  SELECT 
    ARRAY_AGG(DISTINCT name ORDER BY name DESC LIMIT 2) names,
    ARRAY_AGG(DISTINCT age ORDER BY age DESC LIMIT 2) ages
  FROM (
    SELECT 
      CONCAT('(', SUBSTR(CONCAT('00000', CAST(COUNT(1) OVER(PARTITION BY name) AS STRING)), -5), ') ', name) name,
      CONCAT('(', SUBSTR(CONCAT('00000', CAST(COUNT(1) OVER(PARTITION BY age) AS STRING)), -5), ') ', CAST(age AS STRING)) age
    FROM `project.dataset.table`
  )
) t

с результатом

Row names.value names.count ages.value  ages.count   
1   tom         2           20          2    
    alex        2           14          1    
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...