2015-10-14 2 views
0

Я работаю над огромной БД в PostgreSQL. (Извините, если это неправильно отредактировано, я пробовал это часами и все еще работаю над этим)Группа по группам значений

Это часть структуры таблицы, используемой для моего запроса: (таблица user_activities) с некоторыми образцами данных.

+---------------------+---------------------+---------------------+ 
| user_id    | activity   | operation   | 
+---------------------+---------------------+---------------------+ 
| 1     | 1     | 1     | 
| 1     | 1     | 1     | 
| 1     | 1     | 1     | 
| 2     | 1     | 2     | 
| 2     | 1     | 3     | 
| 3     | 1     | 3     | 
| 4     | 1     | 4     | 
| 4     | 1     | 4     | 
| 5     | 1     | 4     | 
| 5     | 1     | 5     | 
| 6     | 3     | 1     | 
| 6     | 3     | 1     | 
| 6     | 3     | 2     | 
| 7     | 3     | 3     | 
| 8     | 3     | 4     | 
| 8     | 3     | 5     | 
+---------------------+---------------------+---------------------+ 

И это мой желаемый результат:

+---------------------+---------------------+---------------------+ 
| count(user_id)  | activity   | operation   | 
+---------------------+---------------------+---------------------+ 
| 4     | 1     | 1,2     | 
| 6     | 1     | 3,4,5    | 
| 6     | 3     | 1,2,3,4,5   | 
+---------------------+---------------------+---------------------+ 

Мне нужно подсчитать user_id для каждого вида деятельности и группы значений операций. Поэтому мне нужно группировать по активности, когда активность равна 1 или 3. (уже сделано это WHERE activity IN (1,3)). Но мне также нужно сгруппировать по операции. Проблема в том, что каждая группа операций будет иметь более 1 значения. Операция может быть 1,2,3,4 и 5. И я хочу объединить группы 1,2, а также группы 3,4,5. Но это еще не все ...

Если я группирую операцию, у меня будет 5 групп для каждого вида деятельности. Мне нужно иметь 2 группы для активности 1 (группы уже указаны) и только одна группа со всеми значениями деятельности, если активность равна 3.

Возможно ли это?

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

+1

Я думаю, вы должны отредактировать свой вопрос и предоставить образцы данных и желаемые результаты (чтобы уточнить, что вы ищете) и запрос, который у вас есть (чтобы помочь кому-либо еще писать запрос). –

+0

@GordonLinoff ok, дай мне минуту, редактирование – AleOtero93

+0

Можете ли вы использовать расширение tablefunc? – dtelaroli

ответ

1

SQL Fiddle Demo

Просто используйте СЛУЧАЙ, чтобы собрать группы, которые вы хотите.

WITH cte as (
    SELECT "user_id", "activity", "operation", 
     CASE 
      WHEN "activity" = 1 THEN 
        CASE 
         WHEN "operation" IN (1,2) THEN '1_first'   
         ELSE '1_second' 
        END 
      WHEN "activity" = 3 THEN '3_first' 
     END as "op_group" 
    FROM user_activities 
) 
SELECT "activity", 
     "op_group", 
     count("user_id"), 
     array_agg(distinct "operation") as "operation" 
FROM cte 
GROUP BY "activity", "op_group" 

ВЫВОД

| activity | op_group | count | operation | 
|----------|----------|-------|-----------| 
|  1 | 1_first |  4 |  1,2 | 
|  1 | 1_second |  6 |  3,4,5 | 
|  3 | 3_first |  6 | 1,2,3,4,5 | 
+1

Я исправляю свой ответ –

+0

У меня вопрос ... можно ли использовать операцию WHEN? IN (1,2) 'вместо операции WHEN« = 1 ИЛИ «операция» = 2'? – AleOtero93

+0

да, я обновляю свой ответ и скрипку с этим изменением –

2

Обновлено для подробной спецификации:

SELECT COUNT(*) as cnt, ua.activity, array_agg(distinct ua.operation) 
FROM users ua 
JOIN (
    SELECT 1 AS activity, 1 as operation, 1 as GROUP_CODE 
    UNION ALL 
    SELECT 1 AS activity, 2 as operation, 1 as GROUP_CODE 
    UNION ALL 
    SELECT 1 AS activity, 3 as operation, 2 as GROUP_CODE 
    UNION ALL 
    SELECT 1 AS activity, 4 as operation, 2 as GROUP_CODE 
    UNION ALL 
    SELECT 1 AS activity, 5 as operation, 2 as GROUP_CODE 
    UNION ALL 
    SELECT 3 AS activity, 1 as operation, 3 as GROUP_CODE 
    UNION ALL 
    SELECT 3 AS activity, 2 as operation, 3 as GROUP_CODE 
    UNION ALL 
    SELECT 3 AS activity, 3 as operation, 3 as GROUP_CODE 
    UNION ALL 
    SELECT 3 AS activity, 4 as operation, 3 as GROUP_CODE 
    UNION ALL 
    SELECT 3 AS activity, 5 as operation, 3 as GROUP_CODE 
) c 
ON ua.activity = c.activity and ua.operation = c.operation 
GROUP BY c.GROUP_CODE, ua.activity 

http://sqlfiddle.com/#!15/46e1f/15


Вот как бы я это сделал. Ниже я создаю динамическую таблицу динамически, но вы также можете иметь таблицу в своей базе данных и присоединиться к ней.

SELECT GROUP_CODE, COUNT(*) as cnt 
FROM user_activities ua 
JOIN (
    SELECT 1 AS activity, 1 as operation, 1 as GROUP_CODE 
    UNION ALL 
    SELECT 1 AS activity, 2 as operation, 1 as GROUP_CODE 
    UNION ALL 
    SELECT 1 AS activity, 3 as operation, 2 as GROUP_CODE 
    UNION ALL 
    SELECT 1 AS activity, 4 as operation, 2 as GROUP_CODE 
    UNION ALL 
    SELECT 1 AS activity, 5 as operation, 2 as GROUP_CODE 
    UNION ALL 
    SELECT 3 AS activity, 1 as operation, 3 as GROUP_CODE 
    UNION ALL 
    SELECT 3 AS activity, 2 as operation, 3 as GROUP_CODE 
    UNION ALL 
    SELECT 3 AS activity, 3 as operation, 3 as GROUP_CODE 
    UNION ALL 
    SELECT 3 AS activity, 4 as operation, 3 as GROUP_CODE 
    UNION ALL 
    SELECT 3 AS activity, 5 as operation, 3 as GROUP_CODE 
) c 
ON ua.activity = c.activity and ua.operation = c.operation 
GROUP BY GROUP_CODE 

Это должно быть довольно быстро - помните SQL предназначен для работы с наборами (таблиц) и присоединяется - это использует присоединяется выполнить логику. Это также хорошо, потому что, если вы сделаете это таблицей, вы можете изменить логику, просто изменив таблицу или добавив несколько «логик» в таблицу, если вы добавите другой столбец для выбора, а затем выберите, какой из них использовать при запуске запроса ,

Я использовал аналогичные методы для взвешенного и персонализированного упорядочения в динамических пользовательских интерфейсах.

2

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

create table test (user_id int, activity int, operation int); 
insert into test values (1,1,1), (1,1,1), (1,1,2), (2,1,3), (2,1,4), (3,3,1), (4,3,3), (4,3,5); 

select count(*), activity, array_agg(operation) 
from test 
group by activity, user_id 

Result: 
| count | activity | array_agg | 
| 3  | 1  | {1,1,2} | 
| 2  | 1  | {3,4}  | 
| 1  | 3  | {1}  | 
| 2  | 3  | {3,5}  | 

На основе отредактированной вопрос, я считаю, что это как бы я решить:

Таблица:

create table test (user_id int, activity int, operation int); 
insert into test values 
(1,1,1),(1,1,1),(1,1,1), 
(2,1,2),(2,1,3), 
(3,1,3), 
(4,1,4),(4,1,4), 
(5,1,4),(5,1,5), 
(6,3,1),(6,3,1),(6,3,2), 
(7,3,3), 
(8,3,4),(8,3,5); 

Запрос:

select count(*), activity, string_agg(distinct operation::VARCHAR, ',') 
from test 
where operation in (1,2) and activity = 1 
group by activity 

UNION ALL 

select count(*), activity, string_agg(distinct operation::VARCHAR, ',') 
from test 
where operation in (3,4,5) and activity = 1 
group by activity 

UNION ALL 

select count(*), activity, string_agg(distinct operation::VARCHAR, ',') 
from test 
where activity = 3 
group by activity 

Результат

count | activity | string_agg 
4  | 1  | 1,2 
6  | 1  | 3,4,5 
6  | 3  | 1,2,3,4,5 
+0

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

+0

Когда я в последний раз видел это, не было 8 пользователей, @Hogan. Сегодня я попытаюсь улучшить ответ. – zedfoxus

+0

Извините, мое плохое из-за его конфуцирования ... Мне действительно нужен сон. Так что я плохо там – AleOtero93

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