2016-11-02 5 views
1

Предположим, у меня есть таблица со следующими данными:Как я могу условно группировать два разных столбца в Oracle?

+----------+-----+--------+ 
| CLASS_ID | Day | Period | 
+----------+-----+--------+ 
| 1  | A | CCR | 
+----------+-----+--------+ 
| 1  | B | CCR | 
+----------+-----+--------+ 
| 2  | A | 1  | 
+----------+-----+--------+ 
| 2  | A | 2  | 
+----------+-----+--------+ 
| 3  | A | 3  | 
+----------+-----+--------+ 
| 3  | B | 4  | 
+----------+-----+--------+ 
| 4  | A | 5  | 
+----------+-----+--------+ 

Как вы могли догадаться из природы данных, я работаю на запрос Oracle SQL, который извлекает данные расписания класса из информационной системы студенческого , Я пытаюсь вывести выражение «период выражения» класса, вычисленное значение, которое содержит поля Day и Period в одном поле. Давайте мои ожидания от пути первого:

  • Если периоды совпадают, период должен быть GROUP BY полем, и Day должны быть агрегированным полем (через LISTAGG функции), поэтому расчетное поле будет CCR (A-B)
  • Если матч дней, день должен быть GROUP BY поля, и Period должны быть агрегированным полем, поэтому расчетное поле будет 1-2 (A)

Я знаю только о том, как сделать каждый GROUP BY в индивидуальном порядке, что-то вроде для того, где Day сек матч:

SELECT 
    day, 
    LISTAGG(period, '-') WITHIN GROUP (ORDER BY period) 
FROM schedule 
GROUP BY day 

и наоборот для согласования Periods, но я не вижу, как я мог бы сделать это динамически для PeriodиDay в том же запросе.

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

Редактировать

Конечный результат должен быть:

+------------+ 
| Expression | 
+------------+ 
| CCR(A-B) | 
+------------+ 
| 1-2(A)  | 
+------------+ 
| 3-4(A-B) | 
+------------+ 
| 5(A)  | 
+------------+ 
+0

Итак, что выход выглядеть, от входов предоставленных вами и с логикой вы объяснить? Кроме того, когда вы говорите о «делать это динамично», что вы подразумеваете под «динамически»? – mathguy

+0

«Динамически» Я просто имею в виду тот факт, что я не думаю, что могу жестко закодировать, какое поле следует сгруппировать. –

+0

Почему не показаны 1-2 и 3 вместе (A)? – mathguy

ответ

1

Это действительно не ясно для меня, ПОЧЕМУ вы хотите производить выход таким образом. Он не дает никакой полезной информации (я не думаю) - вы не можете сказать, например, для class_id = 3, какие комбинации дня и периода фактически используются. Существует четыре возможных сочетания (в соответствии с выходом), но только два находятся в расписании классов.

В любом случае - у вас могут быть свои причины. Вот как вы можете это сделать. Кажется, вы хотите, чтобы LISTAGG и day и period (оба сгруппированы по class_id, они не сгруппированы друг другом). Трудность состоит в том, что вам нужны только отдельные значения в списках агрегатов - без дубликатов. Таким образом, вам нужно будет select distinct, отдельно для period и для day, затем к списку скобок, а затем объединить результаты во внутреннем соединении.

Что-то вроде этого:

with 
    test_data (class_id, day, period) as ( 
     select 1, 'A', 'CCR' from dual union all 
     select 1, 'B', 'CCR' from dual union all 
     select 2, 'A', '1' from dual union all 
     select 2, 'A', '2' from dual union all 
     select 3, 'A', '3' from dual union all 
     select 3, 'B', '4' from dual union all 
     select 4, 'A', '5' from dual 
    ) 
-- end of test data; the actual solution (SQL query) begins below this line 
select a.class_id, a.list_per || '(' || b.list_day || ')' as expression 
from (select class_id, 
       listagg(period, '-') within group (order by period) as list_per 
      from (select distinct class_id, period from test_data) 
      group by class_id 
     ) a 
    inner join 
     (select class_id, 
       listagg(day, '-') within group (order by day) as list_day 
      from (select distinct class_id, day from test_data) 
      group by class_id 
     ) b 
on a.class_id = b.class_id 
; 


CLASS_ID EXPRESSION 
-------- ---------- 
1   CCR(A-B) 
2   1-2(A) 
3   3-4(A-B) 
4   5(A) 
+0

Чтобы определить наличие примеров в образцах данных, я увидел следующее: class_id = 1 - пример 3 (несколько дней, одиночный период), class_id = 2 - пример 2 (Single Day, Multiple Periods) , class_id = 3 - пример 4 (несколько дней, несколько периодов) и class_id = 4 - пример 1 (Single Day, Single Period). –

+0

Что касается * why * Я хочу показать период класса + день таким образом, это знакомый формат, который находится в другом месте в системе, поэтому я решил, что для наших пользователей будет понятно. –

1

Как насчет союза с having count(*) = 1?

select LISTAGG(period, '-') list WITHIN GROUP (ORDER BY period) 
    from schedule 
    group by CLASS_ID, day 
    having count(*) = 1 
union all 
select LISTAGG(day, '-') list WITHIN GROUP (ORDER BY day) 
    from schedule 
    group by CLASS_ID, period 
    having count(*) = 1 
Смежные вопросы