Самый элегантный способ суммировать данные на разных уровнях, используя ARRAY_AGG () И SUM ()? - PullRequest
1 голос
/ 24 апреля 2019

Я хочу подвести итог count на уровне id.Для каждой итоговой строки id мне также нужно поле ARRAY of STRUCTs, которое суммирует данные для каждого из двух атрибутов: a1 и a2.

Вот как мне удалось это сделать, с4 запроса и 6 SELECT операторов, но я думаю, что должен быть более упорядоченный способ сделать это.

1) Для каждого из сводок атрибута выполните ARRAY_AGG() во внешнем запросе послевыполнение SUM() кажется, что это можно сделать за один шаг, хотя нельзя поместить SUM() в и ARRAY_AGG().

2) Выполнение каждого из резюме, сначала на id изатем для каждого атрибута и последующего присоединения ко всем этим также кажется, что это должно быть сделано за один шаг.

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

WITH data AS
((SELECT "A" as id, 1 as count, "a" as a1, "d" as a2)
UNION ALL (SELECT "A", 2, "a", "e")
UNION ALL (SELECT "A", 3, "b", "d")
UNION ALL (SELECT "A", 4, "a", "d")
UNION ALL (SELECT "B", 2, "a", "e")
UNION ALL (SELECT "B", 3, "b", "e")
UNION ALL (SELECT "B", 4, "a", "d")
),

#Summarize on id
datasummary as (
SELECT 
  data.id, SUM(data.count) as total
FROM 
  data
GROUP BY 
  id),

#Summarize in TWO STEPS for a1.  There must be a way to do this in one step?
data2summary as (
SELECT 
  id, ARRAY_AGG(STRUCT(a1, count)) as a1
FROM 
  (SELECT 
    id, a1, SUM(count) as count
  FROM 
    data
  GROUP BY 
    id, a1)
GROUP BY id),


#Summarize in TWO STEPS for a2.  There must be a way to do this in one step?
data3summary as (
SELECT 
  id, ARRAY_AGG(STRUCT(a2, count)) as a2
FROM 
  (SELECT 
     id, a2, SUM(count) as count
   FROM 
     data
   GROUP BY 
     id, a2)
GROUP BY 
  id)

#Join everything in one table
SELECT 
  t.id,  t.total, t2.a1, t3.a2
FROM 
  datasummary t 
    LEFT JOIN data2summary t2 ON t.id = t2.id
    LEFT JOIN data3summary t3 ON t.id = t3.id```

Ответы [ 2 ]

2 голосов
/ 25 апреля 2019

Но я думаю, что здесь должны быть какие-то читабельные "короткие слова", которые мне здесь не хватает.

Ниже приведен тот же результат, что и ваш исходный запрос, хотя он все еще довольно читабелен, прост (и, мне кажется, сексуален)

#standardSQL
CREATE TEMP FUNCTION x(a ANY TYPE) AS (
  ARRAY(SELECT AS STRUCT val, SUM(`count`) `count` FROM UNNEST(a) GROUP BY val)
);
SELECT id, SUM(`count`) AS total,
  x(ARRAY_AGG(STRUCT(a1 AS val, `count`))) a1, 
  x(ARRAY_AGG(STRUCT(a2 AS val, `count`))) a2
FROM data
GROUP BY id   

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

#standardSQL
CREATE TEMP FUNCTION x(a ANY TYPE) AS (
  ARRAY(SELECT AS STRUCT val, SUM(`count`) `count` FROM UNNEST(a) GROUP BY val)
);
WITH data AS (
  SELECT "A" AS id, 1 AS `count`, "a" AS a1, "d" AS a2 UNION ALL 
  SELECT "A", 2, "a", "e" UNION ALL 
  SELECT "A", 3, "b", "d" UNION ALL 
  SELECT "A", 4, "a", "d" UNION ALL 
  SELECT "B", 2, "a", "e" UNION ALL 
  SELECT "B", 3, "b", "e" UNION ALL 
  SELECT "B", 4, "a", "d" 
)
SELECT id, SUM(`count`) AS total,
  x(ARRAY_AGG(STRUCT(a1 AS val, `count`))) a1, 
  x(ARRAY_AGG(STRUCT(a2 AS val, `count`))) a2
FROM data
GROUP BY id   

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

enter image description here

0 голосов
/ 24 апреля 2019

Это немного странно, потому что вы намеренно создаете независимые повторения для групп a1 и a2.Здесь подразумевается, что любой анализ a1 не заботится о a2 и наоборот, так как они не могут быть повторно объединены, если вы потеряли информацию о взаимоотношениях между двумя значениями.

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

SELECT
 id,
 SUM(subtotal) as total,
 ARRAY_AGG(STRUCT(a1, a2, subtotal)) as partial_sums
FROM
(
SELECT
  id,
  a1,
  a2,
  SUM(count) as subtotal
FROM data
GROUP BY id, a1, a2
)
GROUP BY id

Предполагая, что вы сохраняете частичные сводки в виде таблицы, вы можете позже развернуть частичные сводки, чтобы вычислить либо только a1, либо a2-только поломки.В следующем примере используется ANY_VALUE для проецирования итога, поскольку все строки имеют одинаковое значение и избегают дополнительного GROUP BY.Однако построение массива с использованием внешнего запроса может быть совершенно ненужным для варианта использования.

SELECT
   id,
   ANY_VALUE(total) as total,
   ARRAY_AGG(a1_summary) as a1_partial_sums
FROM
(
  SELECT
    id,
    total,
    STRUCT(p.a1, SUM(p.subtotal)) as a1_summary
  FROM
   `partial_summary_table`
  CROSS JOIN UNNEST(partial_sums) as p
  GROUP BY id, total, p.a1
)
GROUP BY id
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...