Структура таблиц такая:
Код: Выделить всё
CREATE TABLE Courses (
CourseID NUMERIC180 NOT NULL,
CourseStartDate INTEGER NOT NULL, // Дата начала курса
CourseEndDate INTEGER NOT NULL, // Дата окончания
DirDepartmentFK NUMERIC180, // Подразделение, которому пренадлежит курс.
PRIMARY KEY (CourseID)
);
CREATE TABLE Subjects (
SubjectID NUMERIC180 NOT NULL,
CourseFK NUMERIC180 NOT NULL,
PRIMARY KEY (SubjectID)
);
CREATE TABLE Clients2Subjects (
ClientFK NUMERIC180 NOT NULL,
SubjectFK NUMERIC180 NOT NULL,
PRIMARY KEY (ClientFK, SubjectFK)
);
Смысл такой: Есть организация занимающиеся обучением. Есть курсы(Courses) которые она проводит. В каждом курсе обязательно есть предметы (Subjects) (>=1). Клиенты, которые приходят на курс - соответственно записываются на предметы(Clients2Subjects).
А надо подсчитать Количество клиентов, которые ходят на курсы, в определенном подразделении в определенный промежуток времени.
Правильный select, следующий:
Код: Выделить всё
SELECT
COALESCE( SUM( (SELECT COUNT(DISTINCT(CS.CLIENTFK)) FROM CLIENTS2SUBJECTS CS
WHERE
CS.SUBJECTFK IN (SELECT SUBJECTID FROM SUBJECTS WHERE COURSEFK=C.COURSEID)
) ), 0)
FROM
COURSES C
WHERE
(SELECT COUNT(*) FROM SUBJECTS WHERE COURSEFK=C.COURSEID)>0 AND
(( ДатаНачалаИзФильтра BETWEEN C.COURSESTARTDATE AND C.COURSEENDDATE ) OR
( ДатаОкончанияИзФильтра BETWEEN C.COURSESTARTDATE AND C.COURSEENDDATE )) AND
DIRDEPARTMENTFK=IDПодразделения
Данный подход дает верные результаты, но он очень долго выполняется. Поэтому я решил перейти к статистике с небольшой погрешностью.
Представим себе такую ситуацию. Есть определенный курс. В этом курсе 10 предметов. На первый, третий предметы ходят 10 человек с ID (ClientID: 1,2,3,4,5,6,7,8,9,10). На второй предмет ходят 2-а человека (ID: 1,2) и т.д. Соответственно, раньше у меня выбиралось и суммировалось с основной статистикой COUNT(DISTINCT(CS.CLIENTFK)) - где были выбраны все клиенты, ходящие на данный курс. Еще раз повторюсь - этот селект - долгий. Сейчас я решил выбрать один ID предмета, но с максимальным количеством человек, ходящем на этот предмет из этого курса, т.е. изменить селект на такое:
Код: Выделить всё
SELECT
COALESCE( SUM( (SELECT COUNT(DISTINCT(CS.CLIENTFK)) FROM CLIENTS2SUBJECTS CS
WHERE
CS.SUBJECTFK = (
ЗДЕСЬ Я ВЫБИРАЮ ОДИН SubjectID, но с максимальным количеством человек, ходящем на данный курс.
SELECT FIRST 1 SUBJECTID
FROM SUBJECTS
WHERE COURSEFK=C.COURSEID
ORDER BY (select count(*) from clients2subjects c2s where c2s.subjectfk=SUBJECTS.subjectid) DESC
) ) ), 0)
FROM
COURSES C
WHERE
(SELECT COUNT(*) FROM SUBJECTS WHERE COURSEFK=C.COURSEID)>0 AND
(( ДатаНачалаИзФильтра BETWEEN C.COURSESTARTDATE AND C.COURSEENDDATE ) OR
( ДатаОкончанияИзФильтра BETWEEN C.COURSESTARTDATE AND C.COURSEENDDATE )) AND
DIRDEPARTMENTFK=IDПодразделения
Последний селект - селект с погрешностью (зато быстро). Например Курс с 2-мя предметами. На первый предмет ходят люди с ID:1,2,3. На второй предмет с ID: 2,3,4,5. Второй селект сосчитает 4-е человека с ID(2,3,4,5). А должен сосчитать с ID:1,2,3,4,5. T.е. правильная статистика - 5 человек.
Какие есть предложения еще?