В любом случае, чтобы сделать заявления о рейтингах умнее? - PullRequest
0 голосов
/ 06 июня 2018

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

Есть ли какие-нибудь советы о том, как это можно улучшить?

Обратите внимание, что фрагменты различаются по размеру (сначала перечисляются самые верхние100, затем фрагменты 100, затем фрагменты 1000, затем один фрагмент 5000 и 3 других фрагмента 15K)

select   
  transaction_code
  ,row_number() over (order by SALES_AMOUNT desc) as rank
  ,SALES_AMOUNT
  ,CASE 
    WHEN rank <=100 THEN to_varchar(rank)
    WHEN rank <=200 then '101-200'
    WHEN rank <=300 then '201-300'
    WHEN rank <=400 then '301-400'
    WHEN rank <=500 then '401-500'
    WHEN rank <=1000 then '501-1000'
    WHEN rank <=1500 then '1001-1500'
    WHEN rank <=2000 then '1501-2000'
    WHEN rank <=2500 then '2001-2500'
    WHEN rank <=3000 then '2501-3000'
    WHEN rank <=3500 then '3001-3500'
    WHEN rank <=4000 then '3501-4000'
    WHEN rank <=4500 then '4001-4500'
    WHEN rank <=5000 then '4501-5000'
    WHEN rank <=5500 then '5001-5500'
    WHEN rank <=6000 then '5501-6000'
    WHEN rank <=6500 then '6001-6500'
    WHEN rank <=7000 then '6501-7000'
    WHEN rank <=7500 then '7001-7500'
    WHEN rank <=8000 then '7501-8000'
    WHEN rank <=8500 then '8001-8500'
    WHEN rank <=9000 then '8501-9000'
    WHEN rank <=95000 then '9001-9500'
    WHEN rank <=10000 then '9501-10000'
    WHEN rank <=15000 then '10001-15000'
    WHEN rank <=30000 then '15001-30000'
    WHEN rank <=45000 then '30001-45000'
    WHEN rank <=60000 then '45001-60000'
    ELSE 'Bottom'
   END AS "TRANSACTION GROUPS"

1 Ответ

0 голосов
/ 06 июня 2018

Самый быстрый способ - создать справочную таблицу, которая сопоставляет ранги с именами групп.Вы можете сделать это, используя JavaScript UDF с сохранением состояния (инициализация карты только один раз).

Но вы также можете просто сделать это в SQL

Определение таблицы

Простое отображение изчисло в строку

create or replace table rank2group(rank integer, grp string);

UDF для генерации имени группы

Ваш код действительно очень длинный.

Вместо этого мы можем создать функцию, которая для данного ранга group_size и group_base (число, из которого формируются группы group_size) генерирует строку.

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

create or replace function group_name(rank integer, group_base integer, group_size integer)
returns varchar
as $$
  (group_base + 1 + group_size * floor((rank - 1 - group_base) / group_size))
  || '-' || 
  (group_base + group_size + group_size * floor((rank - 1 - group_base) / group_size))
$$;

Пример выходных данных:

select group_name(101, 100, 100), group_name(1678, 500, 500), group_name(15000, 10000, 5000);
---------------------------+----------------------------+--------------------------------+
 GROUP_NAME(101, 100, 100) | GROUP_NAME(1678, 500, 500) | GROUP_NAME(15000, 10000, 5000) |
---------------------------+----------------------------+--------------------------------+
 101-200                   | 1501-2000                  | 10001-15000                    |
---------------------------+----------------------------+--------------------------------+

Генерация данных таблицы

Мы сгенерируем значения, отображающие только диапазон 1 .. 60000, используя генераторы Snowflake, group_name и ваш упрощенный оператор CASE:

создать или заменить таблицу rank2group (rank integer, строка grp);

insert into rank2group
select rank,
CASE 
    WHEN rank <=100 THEN to_varchar(rank)
    -- groups of size 100, starting at 100
    WHEN rank <=500 then group_name(rank, 100, 100)                                                    
    WHEN rank <=10000 then group_name(rank, 500, 500)
    -- groups of size 5000, starting at 10000
    WHEN rank <=15000 then group_name(rank, 10000, 5000) 
    WHEN rank <=60000 then group_name(rank, 15000, 15000)
    ELSE 'Bottom'
END AS "TRANSACTION GROUPS"
from (
    select row_number() over (order by 1) as rank
    from table(generator(rowCount=>60000))
);

Использование

Чтобы использовать ее, мы просто присоединяемся к rank.Обратите внимание, вам нужно outer join, а затем ifnull для значений Bottom.Например, используя сгенерированный input, который создает экспоненциально увеличивающиеся числа:

with input as (
  select 1 + (seq8() * seq8() * seq8()) AS rank
  from table(generator(rowCount=>50))
)
select input.rank, ifnull(grp, 'Bottom') grp
from input left outer join rank2group on input.rank = rank2group.rank
order by input.rank;
--------+-------------+
  RANK  |     GRP     |
--------+-------------+
 1      | 1           |
 2      | 2           |
 9      | 9           |
 28     | 28          |
 65     | 65          |
 126    | 101-200     |
 217    | 201-300     |
 344    | 301-400     |
 513    | 501-1000    |
 730    | 501-1000    |
 1001   | 1001-1500   |
 1332   | 1001-1500   |
 1729   | 1501-2000   |
 2198   | 2001-2500   |
 2745   | 2501-3000   |
 3376   | 3001-3500   |
 4097   | 4001-4500   |
 4914   | 4501-5000   |
 5833   | 5501-6000   |
 6860   | 6501-7000   |
 8001   | 8001-8500   |
 9262   | 9001-9500   |
 10649  | 10001-15000 |
 12168  | 10001-15000 |
 13825  | 10001-15000 |
 15626  | 15001-30000 |
 17577  | 15001-30000 |
 19684  | 15001-30000 |
 21953  | 15001-30000 |
 24390  | 15001-30000 |
 27001  | 15001-30000 |
 29792  | 15001-30000 |
 32769  | 30001-45000 |
 35938  | 30001-45000 |
 39305  | 30001-45000 |
 42876  | 30001-45000 |
 46657  | 45001-60000 |
 50654  | 45001-60000 |
 54873  | 45001-60000 |
 59320  | 45001-60000 |
 64001  | Bottom      |
 68922  | Bottom      |
 74089  | Bottom      |
 79508  | Bottom      |
 85185  | Bottom      |
 91126  | Bottom      |
 97337  | Bottom      |
 103824 | Bottom      |
 110593 | Bottom      |
 117650 | Bottom      |
--------+-------------+

Возможная оптимизация

Если ваши диапазоны всегда кратны или равны 100, вы можете сделать таблицу в 100 раз меньше,сохраняются только значения, оканчивающиеся на 00, а затем объединяются, например, CEIL(rank)+1.

Но тогда вам также нужно обрабатывать значения 1..100 после объединения, например, IFNULL(grp, IFF(rank <= 100, rank::varchar, 'Bottom'))

...