SQL группировка по разным значениям в многозначном строковом столбце - PullRequest
1 голос
/ 25 марта 2019

(Я хочу выполнить группирование на основе различных значений в строковом столбце, который имеет несколько значений

В указанном столбце есть список строк в стандартном формате, разделенных запятыми. Потенциальные значениятолько a,b,c,d.

Например, столбец collection (тип: String) содержит:

Row 1: ["a","b"]
Row 2: ["b","c"]
Row 3: ["b","c","a"]
Row 4: ["d"]`

Ожидаемый результат - это число уникальных значений:

collection | count
a | 2
b | 3
c | 2
d | 1

Ответы [ 2 ]

1 голос
/ 25 марта 2019

Что вам нужно сделать, это сначала взорвать столбец коллекции на отдельные строки (как операция flatMap). В красном смещении единственный способ генерировать новых строк - это JOIN - поэтому давайте CROSS JOIN вашей входной таблице со статической таблицей, имеющей последовательные числа, и выбираем только те, которые id меньше или равны числу элементов в коллекции. Затем мы будем использовать функцию split_part, чтобы прочитать элемент с правильным индексом. Как только у нас будет разобранная таблица, мы сделаем простой GROUP BY.

Если ваши элементы хранятся в виде строк массива JSON ('["a", "b", "c"]'), вы можете использовать JSON_ARRAY_LENGTH и JSON_EXTRACT_ARRAY_ELEMENT_TEXT вместо REGEXP_COUNT и SPLIT_PART соответственно.

with 
    index as (
        select 1 as i 
        union all select 2 
        union all select 3 
        union all select 4 -- could be substituted with 'select row_number() over () as i from arbitrary_table limit 4'
    ), 
    agg as (
        select 'a,b' as collection
         union all select 'b,c'
         union all select 'b,c,a'
         union all select 'd'
    )
    select 
        split_part(collection, ',', i) as item,
        count(*)
    from index,agg
    where regexp_count(agg.collection, ',') + 1 >= index.i -- only get rows where number of items matches
    group by 1
1 голос
/ 25 марта 2019

Для всего нижеприведенного я использовал эту таблицу:

create table tmp (
 id INT auto_increment,
 test VARCHAR(255),
 PRIMARY KEY (id)
);

insert into tmp (test) values 
    ("a,b"),
    ("b,c"),
    ("b,c,a"),
    ("d")
;

Если возможные значения только a,b,c,d, вы можете попробовать одно из следующих: Обратите внимание, что это будет работать только в том случае, если вы не очень похожизначения, такие как test и test_new, потому что тогда test будет объединен также со всеми test_new строками, и количество не будет совпадать

select collection, COUNT(*) as count from tmp JOIN (
    select CONCAT("%", tb.collection, "%") as like_collection, collection from (
        select "a" COLLATE utf8_general_ci as collection
        union select "b" COLLATE utf8_general_ci as collection
        union select "c" COLLATE utf8_general_ci as collection
        union select "d" COLLATE utf8_general_ci as collection
    ) tb
) tb1 
ON tmp.test LIKE tb1.like_collection
GROUP BY tb1.collection;

, что даст вам желаемый результат

collection | count
    a      |   2
    b      |   3
    c      |   2
    d      |   1

или вы можете попробовать это

SELECT 
   (SELECT COUNT(*) FROM tmp WHERE test LIKE '%a%') as a_count,
   (SELECT COUNT(*) FROM tmp WHERE test LIKE '%b%') as b_count,
   (SELECT COUNT(*) FROM tmp WHERE test LIKE '%c%') as c_count,
   (SELECT COUNT(*) FROM tmp WHERE test LIKE '%d%') as d_count
;

Результат будет таким:

a_count | b_count | c_count | d_count
2       |    3    |   2     |   1
...