2013-11-26 4 views
2

У меня есть набор данных в форме.Выберите случайный атрибут из группы в Redshift

id | attribute 
----------------- 
1 | a 
2 | b 
2 | a 
2 | a 
3 | c 

Желаемый результат:

attribute| num 
------------------- 
a  | 1 
b,a  | 1 
c  | 1 

В MySQL, я хотел бы использовать:

select attribute, count(*) num 
from 
    (select id, group_concat(distinct attribute) attribute from dataset group by id) as  subquery 
group by attribute; 

Я не уверен, что это может быть сделано в Redshift, потому что он не поддерживает GROUP_CONCAT или любой Psql групповые агрегированные функции, такие как array_agg() или string_agg(). См. this question.

Альтернативное решение, которое сработало бы, если бы у меня был способ выбрать случайный атрибут из каждой группы, а не group_concat. Как это может работать в Redshift?

ответ

0

Это решение, вдохновленный Масаси, проще и осуществляет выбор случайного элемента из группы, в Redshift.

SELECT id, first_value as attribute 
FROM(SELECT id, FIRST_VALUE(attribute) 
    OVER(PARTITION BY id ORDER BY random() 
    ROWS BETWEEN unbounded preceding AND unbounded following) 
    FROM dataset) 
GROUP BY id, attribute ORDER BY id; 
2

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

SQL:

-- (1) uniq dataset 
WITH uniq_dataset as (select * from dataset group by id, attr) 
SELECT 
    uds.id, rds.attr 
FROM 
-- (2) generate random rank for each id 
    (select id, round((random() * ((select count(*) from uniq_dataset iuds where iuds.id = ouds.id) - 1))::numeric, 0) + 1 as random_rk from (select distinct id from uniq_dataset) ouds) uds, 
-- (3) rank table 
    (select rank() over(partition by id order by attr) as rk, id ,attr from uniq_dataset) rds 
WHERE 
    uds.id = rds.id 
AND 
    uds.random_rk = rds.rk 
ORDER BY 
    uds.id; 

Результат:

id | attr 
----+------ 
    1 | a 
    2 | a 
    3 | c 

OR 

id | attr 
----+------ 
    1 | a 
    2 | b 
    3 | c 

Вот таблицы в этом SQL.

-- dataset (original table) 
id | attr 
----+------ 
    1 | a 
    2 | b 
    2 | a 
    2 | a 
    3 | c 

-- (1) uniq dataset 
id | attr 
----+------ 
    1 | a 
    2 | a 
    2 | b 
    3 | c 

-- (2) generate random rank for each id 
id | random_rk 
----+---- 
    1 | 1 
    2 | 1 <- 1 or 2 
    3 | 1 

-- (3) rank table 
rk | id | attr 
----+----+------ 
    1 | 1 | a 
    1 | 2 | a 
    2 | 2 | b 
    1 | 3 | c 
+0

Это работает, спасибо!Это также дало мне идею более простого способа написать аналогичный запрос: – dima

+0

SELECT id, атрибут first_value FROM (FROM() SELECT id, FIRST_VALUE (атрибут) OVER (PARTITION BY ORDER BY random() ROWS МЕЖДУ неограниченным предыдущим AND неограниченным следующим) FROM dataset) GROUP BY id, attribute ORDER BY id; – dima

+0

@dima в интересах сообщества, вы должны либо принять ответ Масаси, либо добавить свое собственное решение в качестве ответа и принять его. – Sim

-2

я не проверил этот запрос, но эти функции поддерживаются в Redshift:

select id, arrary_to_string(array(select attribute from mydataset m where m.id=d.id),',') from mydataset d

+0

К сожалению, RedShift не поддерживает функцию array_to_string. http://docs.aws.amazon.com/redshift/latest/dg/String_functions_header.html –

+0

Это не часть официальной документации, но это действительная функция в Redshift. Например, я использую его для грантовых схем: select 'grant' || substring (случай, когда charindex ('U', split_part (split_part (array_to_string (nspacl, '|'), pu.usename, 2), '/', 1))> 0 then ', use' else '' end || case, когда charindex ('C', split_part (split_part (array_to_string (nspacl, '|'), pu.usename, 2), '/', 1))> 0 then ', create' else '' end , 2, 10000) || 'on schema' || nspname || ' к "'|| pu.usename ||'"; ' из pg_namespace pn, pg_user pu, где array_to_string (nspacl, ','), например '%' || pu.usename || '%' –

0

Это ответ на соответствующий вопрос here. Этот вопрос закрыт, поэтому я отправляю ответ здесь.

Вот метод для агрегирования столбец в строку:

select * from temp; 
attribute 
----------- 
a 
c 
b 

1) Дайте уникальный ранг каждой строки

with sub_table as(select attribute, rank() over (order by attribute) rnk from temp) 
select * from sub_table; 

attribute | rnk 
-----------+----- 
a   | 1 
b   | 2 
c   | 3 

2) С помощью оператора Concat || для объединения в одну линию

with sub_table as(select attribute, rank() over (order by attribute) rnk from temp) 
select (select attribute from sub_table where rnk = 1)|| 
     (select attribute from sub_table where rnk = 2)|| 
     (select attribute from sub_table where rnk = 3) res_string; 

res_string 
------------ 
abc 

Это работает только для конечного числа строк (X) в этом столбце. Это могут быть первые X строк, упорядоченные некоторым атрибутом в предложении «order by». Я предполагаю, что это дорого.

Оператор case может использоваться для обработки NULL, которые возникают, когда определенного ранга не существует.

with sub_table as(select attribute, rank() over (order by attribute) rnk from temp) 
select (select attribute from sub_table where rnk = 1)|| 
     (select attribute from sub_table where rnk = 2)|| 
     (select attribute from sub_table where rnk = 3)|| 
     (case when (select attribute from sub_table where rnk = 4) is NULL then '' 
      else (select attribute from sub_table where rnk = 4) end) as res_string; 
Смежные вопросы