Вы используете слово «оптимизировать» в заголовке вопроса без объяснения причин что вы хотите оптимизировать.
Если вы говорите о производительности запроса, то у вас нет проблем. Количество записей, которые вы можете получить, зависит от количества сеансов, которые у вас есть каждый день (потому что только одна команда может посещать любой сеанс). Если вы проводите десять сеансов в день, это триста записей в месяц. Если вы проводите сто сессий в день, что составляет три тысячи записей в месяц. Это не большие объемы данных. Таким образом, вы делаете плохое решение, искажая свой дизайн базы данных, чтобы избежать проблем с производительностью, которых нет.
Вы упомянули электронные таблицы в одном из своих комментариев. Это не плохой дизайн. В верхней строке есть сеансы, в стороне есть команды, а ячейки показывают, присутствовала ли команда на сеансе. Они сопоставляются с тремя таблицами базы данных: СЕССИЯМИ, ТИПАМИ и таблицей пересечений TEAM_SESSIONS. Вам нужна только запись в TEAM_SESSIONS, когда команда посещала сеанс.
В качестве доказательства концепции я выбил три таблицы в Oracle.
SQL> desc teams
Name Null? Type
----------------------------------------- -------- ----------------------------
ID NOT NULL NUMBER
NAME VARCHAR2(20 CHAR)
SQL> desc sessions
Name Null? Type
----------------------------------------- -------- ----------------------------
ID NOT NULL NUMBER
SSN_DAY DATE
SSN_START NUMBER(4,2)
SSN_END NUMBER(4,2)
SQL> desc team_sessions
Name Null? Type
----------------------------------------- -------- ----------------------------
TEAM_ID NOT NULL NUMBER
SESSION_ID NOT NULL NUMBER
SQL>
Функция PIVOT введена в Oracle 11g делает его подпруга, чтобы сколотить матрицу (различные ароматы СУБД будут иметь разные способы приблизиться к этому). Как вы можете видеть, три команды сегодня забронировали сеансы, никто не хочет тренироваться в обеденное время, а Bec United - как горчица (или нужна тренировка)!
SQL> select * from (
2 select t.name as team_name
3 , trim(to_char(s.ssn_start))||'-'||trim(to_char(s.ssn_end)) as ssn
4 , case when ts.team_id is not null then 1 else 0 end as present
5 from sessions s
6 cross join teams t
7 left outer join team_sessions ts
8 on (ts.team_id = t.id
9 and ts.session_id = s.id)
10 where s.ssn_day = trunc(sysdate)
11 )
12 pivot
13 (sum (present)
14 for ssn in ('9-11', '11-13', '13-15', '15-17', '17-19')
15 )
16 order by team_name
17/
TEAM_NAME '9-11' '11-13' '13-15' '15-17' '17-19'
-------------------- ---------- ---------- ---------- ---------- ----------
Balham Blazers 0 1 0 0 0
Bec United 1 0 0 0 1
Dinamo Tooting 0 0 0 0 0
Melchester Rovers 0 0 0 1 0
SQL>
Во всяком случае, Достоинство этой модели данных является то, что он является гибким. Мы можем подсчитать, как часто группа посещает, сколько времени они посещают, в какой день недели они посещают, какие сессии всегда забронированы, какие сеансы редко забронированы и т. Д. Кроме того, легко управлять данными. В частности, преимущество трех табличного решения всего за две таблицы состоит в том, что проще предотвратить двойные заказы и нестандартные или перекрывающиеся временные интервалы.
Вы видите, нормализация - это не только какой-то лунный язык, который мы используем для того, чтобы одурачить невиновного, он предлагает реальные практические преимущества. Есть несколько сценариев, где движение вниз по крайней мере до BCNF - не лучшая идея.
am, поворачиваясь к этой модели. как бы вы запрашивали все записи посещаемости пользователей в течение месяца? Как бы вы присоединились к таблице AttMst? – Sam
'select date, userid from AttMst am, объявление AttDet, где am.id = ad.id group by date. Это будет отображаться по дате. Но это непроверенный запрос, пожалуйста, проверьте его. – Himadri