SQL / HiveQL для присвоения значений сегментам на основе таблицы - PullRequest
0 голосов
/ 09 ноября 2018

У меня есть таблица "bucket", содержащая минимальные значения int для сегментов, например,

min_value bucket_id
--------- ---------
       0      1
   12345      2
   67890      3

т.е. любое значение> = 0 и <12345 принадлежит сегменту 1, ..., любое значение> = 67890 принадлежит сегменту 3.

и таблица значений int "value", например:

id value
-- -----
11    10
22 20000
33 80000

Я бы хотел выяснить, к какому сегменту относится каждое значение. Так

select id, bucket_id
from (some join, or whatever, of bucket and value)

дает мне

id bucket_id
-- ---------
11     1
22     2
33     3

Я пытаюсь реализовать это в HiveQL. Есть идеи?

Ответы [ 3 ]

0 голосов
/ 09 ноября 2018

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

> select * from bucket;
+-------------------+-------------------+--+
| bucket.min_value  | bucket.bucket_id  |
+-------------------+-------------------+--+
| 0                 | 1                 |
| 12345             | 2                 |
| 67890             | 3                 |
+-------------------+-------------------+--+

> select * from buckvalue;
+---------------+------------------+--+
| buckvalue.id  | buckvalue.value  |
+---------------+------------------+--+
| 11            | 10               |
| 22            | 20000            |
| 33            | 80000            |
+---------------+------------------+--+

> select bucket_id, min_value, lead(min_value) over(order by bucket_id)  as max1 from bucket;
INFO  : OK
+------------+------------+--------+--+
| bucket_id  | min_value  |  max1  |
+------------+------------+--------+--+
| 1          | 0          | 12345  |
| 2          | 12345      | 67890  |
| 3          | 67890      | NULL   |
+------------+------------+--------+--+

> select t1.id, t1.value, t2.bucket_id from buckvalue t1 left outer join ( select bucket_id, min_value, lead(min_value) over(order by bucket_id)  as max1 from bucket ) t2
where t1.value >= t2.min_value and t1.value < coalesce(t2.max1,99999);

+--------+-----------+---------------+--+
| t1.id  | t1.value  | t2.bucket_id  |
+--------+-----------+---------------+--+
| 11     | 10        | 1             |
| 22     | 20000     | 2             |
| 33     | 80000     | 3             |
+--------+-----------+---------------+--+
0 голосов
/ 09 ноября 2018

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

create temporary table bucket as select * from (select 0 min_value, 1 bucket_id union select 12345, 2 union select 67890, 3) a;
create temporary table value as select * from (select 11 id, 10 value union select 22, 20000 union select 33, 80000) a;

select value.id, max(bucket.bucket_id) bucket_id
from value
join bucket
where value.value > bucket.min_value
group by value.id;
0 голосов
/ 09 ноября 2018

Я предположил, что условие для сегмента с наибольшим min_value равно min_value <= value (поскольку нет сегмента с большим min_value), и я также предположил целочисленный тип для столбца value таблицы value и столбца min_value таблицы bucket (это важно, потому что запрос использует сравнение, которое работает по-разному в случае строкового типа, поэтому вам нужно выполнить приведение типов для строки).

Следующий запрос работает для неотрицательных value таблиц value, в случае использования отрицательных значений необходимо заменить
max(if(a.value >= b.min_value, b.min_value, 0))
с
max(if(a.value >= b.min_value, b.min_value, <minimum possible value that "value" field may have>)):

select 
c.id, 
if(d.bucket_id is null, 'not in bucket', d.bucket_id)

from
(    
  select     
  a.id,
  max(if(a.value >= b.min_value, b.min_value, 0)) as bucket_min_value    
  from    
  value a    
  left join     
  bucket b    
  group by a.id    
)    
c

left join    
bucket d    
on c.bucket_min_value = d.min_value    
;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...