SQL: создание столбцов из отдельных значений столбца

Я пытаюсь сделать запрос, основанный на отдельном значении определенного столбца таблицы. Я использую сервис Bigquery из Google Cloud.

Вот как выглядит моя таблица:

Дата Тип Расположение Имя Группа 2022-07 Тип 1 Местоположение1 Имя1 Группа 1 2022-07 Тип2 Местоположение1 Имя2 Группа2 2022-08 Тип 1 Местоположение2 Имя3 Группа2 ... ... ... ... ...

Я хочу подсчитать количество каждого Type для каждого конкретного места. Проблема в том, что существует большое количество разных Type и Location.

Вот что я обычно делаю:

SELECT DISTINCT Location,
COUNT(DISTINCT CASE WHEN Type = Type1 THEN Name END),
COUNT(DISTINCT CASE WHEN Type = Type2 THEN Name END),
COUNT(DISTINCT CASE WHEN Type = Type3 THEN Name END),
... #same thing for all types
FROM `table`
WHERE Group = "Group1" OR Group = "Group2"
GROUP BY Location

Мне было интересно, есть ли способ получить все значения из столбца Type и выполнить итерацию для автоматического создания столбца без необходимости вручную вводить его, чтобы получить что-то вроде этого:

SELECT DISTINCT Location,
iterate on Type[n]
COUNT(DISTINCT CASE WHEN Type = Type[n] THEN Name END)
FROM `table`
WHERE Group = "Group1" OR Group = "Group2"
GROUP BY Location

Чтобы получить:

Расположение Тип 1 Тип2 Тип3 ... Местоположение1 n_Type1 n_Type2 n_Type3 ... Местоположение2 n_Type1 n_Type2 n_Type3 ... Местоположение3 n_Type1 n_Type2 n_Type3 ... ... ... ... ... ...

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

Вот мой SQL-запрос с использованием PIVOT (не работает):

EXECUTE IMMEDIATE(SELECT '''
SELECT Location, REPLACE(Type, " ", "_") AS Type,
COUNT(Distinct Name) AS Nbr
FROM `table`
WHERE Group LIKE "Group1" 
OR Group LIKE "Group2"
GROUP BY Location,  Type
PIVOT (any_value(Result) for Type in (''' || string_agg(distinct "'" || REPLACE(Type, " ", "_") || "'") || 
"))"
FROM `table`
)

Заранее спасибо за ответ! Хорошего дня!

так как некоторые типы имеют пробелы --> type1 и type 1 следует считать одинаковыми?

Jaytiger 21.02.2023 13:07

Нет, они разные

Hibann 21.02.2023 14:38
ReactJs | Supabase | Добавление данных в базу данных
ReactJs | Supabase | Добавление данных в базу данных
Это и есть ваш редактор таблиц в supabase.👇
Понимание Python и переход к SQL
Понимание Python и переход к SQL
Перед нами лабораторная работа по BloodOath:
0
2
56
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Кажется, вам нужен агрегированный и сводной запрос.

1-й шаг: агрегация

SELECT Location, Type, COUNT(Name) Count 
  FROM sample_table 
 GROUP BY 1, 2;

Это возвращает сложенный (несвернутый) результат, как показано ниже.

2-й шаг: поворот

Как только вы повернете предыдущий результат, вы получите желаемый результат.

SELECT * FROM (
  SELECT Location, Type, COUNT(Name) Count 
    FROM sample_table 
   GROUP BY 1, 2
) PIVOT (ANY_VALUE(Count) FOR Type IN ('Type1', 'Type2', 'Type3'));

3-й шаг: динамический запрос

итерация по Type[n] COUNT (ОТЛИЧНЫЙ СЛУЧАЙ, КОГДА Тип = Тип [n], ТОГДА Имя КОНЕЦ)

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


Обновлено

CREATE TEMP TABLE `sample_table` AS
  SELECT '2022-07' Date, 'Type1' Type, 'Location1' Location, 'Name1' Name, 'Group1' `Group` UNION ALL
  SELECT '2022-07' Date, 'Type2' Type, 'Location1' Location, 'Name2' Name, 'Group2' `Group` UNION ALL
  SELECT '2022-08' Date, 'Type 1' Type, 'Location2' Location, 'Name3' Name, 'Group2' `Group`
;

-- before using a dynamic sql
SELECT * FROM (
  SELECT Location, REPLACE(Type, " ", "_") AS Type,
         COUNT(Distinct Name) AS Nbr
    FROM `sample_table`
   WHERE `Group` LIKE "Group1" OR `Group` LIKE "Group2"
   GROUP BY Location, Type
)  PIVOT (ANY_VALUE(Nbr) FOR Type IN ('Type1', 'Type2', 'Type_1'));

-- using a dynamic sql
EXECUTE IMMEDIATE FORMAT("""
SELECT * FROM (
  SELECT Location, REPLACE(Type, " ", "_") AS Type,
         COUNT(Distinct Name) AS Nbr
    FROM `sample_table`
   WHERE `Group` LIKE "Group1" OR `Group` LIKE "Group2"
   GROUP BY Location, Type
)  PIVOT (ANY_VALUE(Nbr) FOR Type IN ('%s'))
""", (SELECT STRING_AGG(DISTINCT REPLACE(Type, ' ', '_'), "','")
        FROM `sample_table`
       WHERE `Group` LIKE 'Group1' OR `Group` LIKE 'Group2'
     ));

Я пытаюсь выполнить эти шаги, но я борюсь с самой командой поворота, как вы сказали, она должна быть динамической, и для этого мне нужно использовать команду EXECUTE IMMEDIATE(). Я предполагаю, что проблема заключается в синтаксисе моего сводного запроса, но я пока не вижу ошибки.

Hibann 21.02.2023 14:44

Я проверил ваш ответ, я получаю сообщение об ошибке: «Недопустимый символ спецификатора формата «V» в строке FORMAT». Я вижу, что вы пытаетесь сделать с этим ответом, и я думаю, что это правильный подход, возможно, это ошибка моя сторона

Hibann 21.02.2023 15:42

Если вы запустите запрос как есть, он будет успешным, поэтому еще раз взгляните на свой код, а также проверьте данные, которые вы тестируете. и если вы по-прежнему получаете сообщение об ошибке, дайте мне знать с фактическим запросом, который вы тестируете.

Jaytiger 21.02.2023 15:50

каким-либо изменением, вы используете % в своем запросе, например LIKE 'Group%' или что-то в этом роде?

Jaytiger 21.02.2023 15:52

Да, я для того, чтобы фильтровать группы по своему выбору, в обоих случаях

Hibann 21.02.2023 15:59

Если это так, вам нужно экранировать % с помощью дополнительной % в функции format(), см. здесь stackoverflow.com/questions/75397329/…

Jaytiger 21.02.2023 16:01

Отлично, побег с дополнительным % помог, спасибо за помощь

Hibann 21.02.2023 16:06

Другие вопросы по теме