2017-02-05 3 views
0

Рассмотрим столбец массива строк в таблице, содержащей категориальные данные. Есть ли простой способ конвертировать эту схему, так что есть number of categories булевых столбцов, представляющих двоичную кодировку этого категориального столбца?Преобразование категориального столбца в двоичное представление в SQL

Пример:

id  type 
------------- 
1  [A, C] 
2  [B, C] 

преобразуется в:

id is_A  is_B is_C 
1  1  0  1 
2  0  1  1 

Я знаю, что могу сделать это 'вручную', то есть с помощью:

WITH flat AS (SELECT * FROM t, unnest(type) type), 
mid AS (SELECT id, (type='A') as is_A, (type='B') AS is_B, (type='C') as is_C) 
SELECT id, SUM(is_A), SUM(is_B), SUM(is_C) FROM mid GROUP BY id 

Но я ищу решение, которое работает, когда число категорий составляет около 1-10K. . Кстати, я использую BigQue ry SQL.

+0

вы пробовали? –

ответ

1

ищет решение, которое работает, когда количество категорий составляет около 1-10K

Ниже для BigQuery SQL

Шаг 1 - производить динамически запроса (по аналогии с той, которая используется в вашем вопросе - но теперь она строится динамически основывают на вас столе - yourTable)

#standardSQL 
WITH categories AS (SELECT DISTINCT cat FROM yourTable, UNNEST(type) AS cat) 
SELECT CONCAT(
    "WITH categories AS (SELECT DISTINCT cat FROM yourTable, UNNEST(type) AS cat), ", 
    "ids AS (SELECT DISTINCT id FROM yourTable), ", 
    "pairs AS (SELECT id, cat FROM ids CROSS JOIN categories), ", 
    "flat AS (SELECT id, cat FROM yourTable, UNNEST(type) cat), ", 
    "combinations AS (", 
    " SELECT p.id, p.cat AS col, IF(f.cat IS NULL, 0, 1) AS flag ", 
    " FROM pairs AS p LEFT JOIN flat AS f ", 
    " ON p.cat = f.cat AND p.id=f.id ", 
    ") ", 
    "SELECT id, ", 
    STRING_AGG(CONCAT("SUM(IF(col = '", cat, "', flag, 0)) as is_", cat) ORDER BY cat), 
    " FROM combinations ", 
    "GROUP BY id ", 
    "ORDER BY id" 
) as query 
FROM categories 

Шаг 2 - скопируйте результат вышеуказанного запроса, вставьте его обратно в веб-интерфейс и запустите запрос

Думаю, у вас есть идея. Yo может реализовать его, как описано выше чисто в SQL или вы можете сгенерировать окончательный запрос в любой клиент по вашему выбору

Я пытался этот подход генерации запроса (но в Python) проблема в том, что запрос может легко достичь предела 256KB размера запроса в BigQuery

во-первых, давайте посмотрим, как «легко» это достичь предела 256KB
Если у вас есть 10 символов, как средняя длина категории - в этом случае вы можете покрыть с этим подходом - около 4750 категорий.
С 20 в среднем - охват составляет около 3480 и 30 - 2750

Если вы «сжать» SQL немного, удаляя пробелы и AS, и т.д. Вы можете сделать это, соответственно: 5400, 3800, 2970 для соответственно 10, 20, 30 символов

Так что, я бы сказал - да/Согласитесь - это, скорее всего, предел досягаемости до того 5K в реальном случае

Итак, во-вторых, давайте посмотрим, если это на самом деле большая проблема !
Как пример, предположим, что вам нужны категории 6K.Посмотрим, как вы можете разделить это на две партии (при условии, что сценарий 3K действительно работает в соответствии с первоначальным решением).
Нам нужно разделить категории на две группы - только на основе названий категорий
Итак, первая группа будет - МЕЖДУ «cat1» и «cat3000»
и вторая группа будет - между «cat3001» и «cat6000»

Итак, теперь работают обе группы с Step1 и Step2 с TEMP1 и temp2 таблиц как назначения
На шаге 1 - добавить (в самом низу запроса - после FROM categories

WHERE cat BETWEEN ‘cat1’ AND ‘cat3000’ 

для первой партии, и

WHERE cat BETWEEN ‘cat3001’ AND ‘cat6000’ 

для второй партии

Теперь перейдите к шагу 3

Шаг 3 - Объединение частичных результатов

#standardSQL 
SELECT * EXCEPT(id2) 
FROM temp1 FULL JOIN (
    SELECT id AS id2, * EXCEPT(id) FROM temp2 
) ON id = id2 
-- ORDER BY id 

Вы можете проверить последнюю логику с менее простыми/фиктивными данными

WITH temp1 AS (
    SELECT 1 AS id, 1 AS is_A, 0 AS is_B UNION ALL 
    SELECT 2 AS id, 0 AS is_A, 1 AS is_B UNION ALL 
    SELECT 3 AS id, 1 AS is_A, 0 AS is_B  
), 
temp2 AS (
    SELECT 1 AS id, 1 AS is_C, 0 AS is_D UNION ALL 
    SELECT 2 AS id, 1 AS is_C, 0 AS is_D UNION ALL 
    SELECT 3 AS id, 0 AS is_C, 1 AS is_D  
) 

Выше может быть легко расширен до более чем только две партий

Надеется, что это помогло

+0

Я попытался использовать этот метод генерации запроса (но в Python), проблема заключается в том, что запрос может легко достичь предела размера запроса 256KB в BigQuery. –

+0

@ S.Mohsensh - см. Дополнение к моему ответу –

+0

@ S.Mohsensh - Если мой ответ помог вам, и вы его приняли, пожалуйста, также подумайте о его голосовании (если вы уже не сделали: o). Подробнее см. На странице http://stackoverflow.com/help/someone-answers и Upvote в http://meta.stackexchange.com/questions/5234/how-does-accepting-an-answer-work#5235. –

Смежные вопросы