Повторное использование агрегированных вычислений в разных частях инструкции CASE

#google-bigquery #case #aggregate-functions

#google-bigquery #случай #агрегатные функции

Вопрос:

У меня есть таблица myTable с таблицей с одним столбцом, содержащая целое число, представляющее однобайтовое значение, подобное этому:

 status_code
-----------
(single bit values:)
1
2
4
8
(multiple bit values:)
...
12
3
etc.
  

Я выбираю общий «статус» на основе общей доли битов, которые соответствуют определенному значению, используя логику, которая выглядит следующим образом. Как вы можете видеть, есть небольшое повторение, когда я повторно выполняю некоторые идентичные вычисления:

 select 
       (case when (sum(case when status_code >> 4 = 1 then 1 else 0 end) / count(*))   
                  (sum(case when status_code >> 3 = 1 then 1 else 0 end) / count(*)) > 0.75
             then 0
       else 
          case when (sum(case when status_code >> 4 = 1 then 1 else 0 end) / count(*))   
                    (sum(case when status_code >> 3 = 1 then 1 else 0 end) / count(*))  
                    (sum(case when status_code >> 2 = 1 then 1 else 0 end) / count(*)) > 0.75
               then 1
          else 
               case when (sum(case when status_code >> 4 = 1 then 1 else 0 end) / count(*))   
                         (sum(case when status_code >> 3 = 1 then 1 else 0 end) / count(*))  
                         (sum(case when status_code >> 2 = 1 then 1 else 0 end) / count(*))  
                         (sum(case when status_code >> 1 = 1 then 1 else 0 end) / count(*)) > 0.75
                    then 2
               else 
                 3
               end
          end
        end) as status 
from myTable
  

Как я могу упростить запрос (и, возможно, сделать его более производительным), повторно используя вычисленные пропорции каждого отдельного статуса? Например, как я мог бы использовать псевдоним следующего и повторно использовать его в разных частях инструкции case?

 (sum(case when status_code >> 4 = 1 then 1 else 0 end) / count(*))
  

Возможно ли это вообще?

Комментарии:

1. Знаете ли вы о битовой функции bigquery? cloud.google.com/bigquery/docs/reference/standard-sql /…

2. Спасибо @Tamier Klein. Это подсчитывает количество битов, представленных в каждом байте, тогда как я подсчитываю пропорции, которые были установлены для каждого бита, во всех записях

Ответ №1:

Как я могу упростить запрос?

Я думаю, что ниже приведен один из вариантов

 #standardSQL
CREATE TEMP FUNCTION f(code INT64, bits INT64) AS (
  IF(code >> bits = 1, 1, 0)
);
SELECT (CASE 
  WHEN (SUM(f(status_code, 4))   
    SUM(f(status_code, 3))) / COUNT(*) > 0.75 THEN 0
  WHEN (SUM(f(status_code, 4))    
    SUM(f(status_code, 3))   
    SUM(f(status_code, 2))) / COUNT(*) > 0.75 THEN 1
  WHEN (SUM(f(status_code, 4))   
    SUM(f(status_code, 3))  
    SUM(f(status_code, 2))  
    SUM(f(status_code, 1))) / COUNT(*) > 0.75 THEN 2
  ELSE 3
  END) AS status 
FROM `project.dataset.table`
  

или дальнейший «рефакторинг» дает:

 #standardSQL
CREATE TEMP FUNCTION f(code INT64, bits INT64) AS (
  IF(code >> bits = 1, 1, 0)
);
SELECT 
  (CASE 
    WHEN SUM(f(status_code, 4)   f(status_code, 3)) / COUNT(*) > 0.75 THEN 0
    WHEN SUM(f(status_code, 4)   f(status_code, 3)   f(status_code, 2)) / COUNT(*) > 0.75 THEN 1
    WHEN SUM(f(status_code, 4)   f(status_code, 3)   f(status_code, 2)   f(status_code, 1)) / COUNT(*) > 0.75 THEN 2
    ELSE 3
  END) AS status 
FROM `project.dataset.table`
  

и, вероятно, сделать его более производительным…

Итак, наконец

 #standardSQL
CREATE TEMP FUNCTION f(code INT64, bits INT64) AS (
  IF(code >> bits = 1, 1, 0)
);
SELECT 
  (CASE 
    WHEN f4   f3 > 0.75 THEN 0
    WHEN f4   f3   f2 > 0.75 THEN 1
    WHEN f4   f3   f2   f1 > 0.75 THEN 2
    ELSE 3
  END) AS status 
FROM (
  SELECT 
    SUM(f(status_code, 4))/ COUNT(*) f4, 
    SUM(f(status_code, 3))/ COUNT(*) f3, 
    SUM(f(status_code, 2))/ COUNT(*) f2, 
    SUM(f(status_code, 1))/ COUNT(*) f1 
  FROM `project.dataset.table`
)