Использование ORDER BY в группирующем запросе
Начиная с Firebird версии 1.5, элементы в списке ORDER BY В группирующем запросе должны быть либо агрегатными функциями, допустимыми в контексте группирования, либо элементами, которые представлены в списке GROUP BY.
Firebird 1.0.x является менее ограничивающим- он допускает упорядочение по элементам или выражениям, находящимся вне контекста группирования.
Улучшенные условия группирования
Firebird 1.5 и более поздние версии поддерживают некоторые дополнительные условия группирования, недоступные в версии 1.0.x.
Группируемое поле, которое связано с выражением подзапроса, может содержать агрегатное выражение, ссылающееся на элемент агрегатного выражения в списке
GROUP BY.
В следующем примере реентерабельный подзапрос к системной таблице RDB$RELATION_FIELDS содержит агрегатное выражение (MAX(I:.RDB$FIELD_POSITION)), результат которого используется для локализации имени (RDB$FIELD_NAME) столбца, имеющего наибольший номер позиции для каждой таблицы (RDB$RELATION_NAME) в базе данных:
SELECT
r.RDB$RELATION_NAME,
MAX(r.RDB$FIELD_POSITION) AS MAXFIELDPOS,
(SELECT
r2,RDB$FIELD_NAME FROM RDB$RELATION_FIELDS r2
WHERE
r2.RDB$RELATION _NAME = r.RDB$RELATION_NAME
and r2.RDB$FIELD_POSITION = MAX(r.RDB$FIELD_POSITION)) AS FIELDNAME
FROM RDB$RELATI ON_FIELDS r
/* мы используем предложение WHERE для фильтрации системных таблиц */
WHERE r,RDB$RELATION NAME NOT STARTING WITH 'RDB$'
GROUP BY 1;
RDB$RELATION_NAME | MAXFIELDPOS | FIELDNAME |
=========== | ============ | ========= |
COUNTRY | 1 | CURRENCY |
CROSS_RATE | 3 | UPDATE_DATE |
CUSTOMER | 11 | ON_HOLD |
DEPARTMENT | 6 | PHONE_NO |
EMPLOYEE | 10 | FOLL_NAME |
EMPLOYEE_PROJECT | 1 | PROJ_ID |
JOB | 7 | LANGUAGE_REQ |
PHONE_LIST | 5 | PHONE_NO |
PROJECT | 4 | PRODUCT |
PROJ_DEPT_BUDGET | 4 | PROJECTED_BUDGET |
SALARY_HISTORY | 5 | NEW_SALARY |
SALES | 12 | AGED |
Теперь в тех же самых текстах мы используем COUNT() для подсчета количества столбцов, хранимых в каждой таблице:
SELECT
rf.RDB$RELATION_NAME AS "Table Name", (
SELECT
r.RDB$RELATION_ID
FROM RDB$RELATIONS r
WHERE r.RDB$RELATION_NAME = rf.RDB$RELATION_NAME) AS ID,
COUNT(*) AS "Field Count"
FROM RDB$RELATION_FIELDS rf
WHERE rf,RDB$RELATION_NAME NOT STARTING WITH 'RDB$'
GROUP BY
rf.RDB$RELATION NAME;
Table Name | ID | Field Count |
COUNTRY | 128 | 2 |
CROSS_RATE | 139 | 4 |
CUSTOMER | 137 | 12 |
DEPARTMENT | 130 | 7 |
... и т.д.
Выражение агрегатной функции- COUNT(), AVG() и т.д.- может принимать аргумент, который является выражением подзапроса, возвращающим скалярное значение. Например, далее результат запроса SELECT COUNT(*) передается на более высокий уровень в выражение SUMO, которое для каждой таблицы (RDB$RELATION_NAME) выводит произведение счетчика полей на количество индексов в таблице:
SELECT
r.RDB$RELATION_NAME,
SUM((SELECT COUNT(*) FROM RDB$RELATION_FIELDS rf
WHERE rf,RDB$RELATION_NAME = r.RDB$RELATION_NAME))
AS "Fields * Indexes"
FROM RDB$RELATIONS r
JOIN RDB$INDICES i
ON (i.RDB$RELATION_NAME = r.RDBSRELATION_NAME)
WHERE r.RDB$RELATION_NAME NOT STARTING WITH 'RDB$'
GROUP BY r.RDB$RELATION_NAME;
RDB$RELATION NAME Fields * Indexes
COUNTRY 2
CROSS_RATE 4
CUSTOMER 48
DEPARTMENT 35
... и т.д.
Агрегатные функции для различных уровней группирования могут быть перемешаны в одном и том же группирующем запросе.
В следующем примере результат выражения, полученный из подзапроса, который выполняет COUNT() для столбца на самом низком уровне группы (RDB$INDICES), передается на уровень группирования. Предложение HAVING выполняет фильтрацию, определяемую двумя другими агрегатными функциями на нижнем уровне группы.
SELECT
r.RDB$RELATION_NAME,
MAX(i.RDB$STATISTICS) AS "Maxl",
/* одно агрегатное выражение, вложенное в другое */
(SELECT COUNT(*) || ' - ' || MAX(i.RDB$STATISTICS)
FROM RDB$RELATION_FIELDS rf
WHERE rf.RDB$RELATION_NAME = r.RDB$RELATION_NAME) AS "Max2"
FROM
RDB$RELAT IONS r
JOIN RDB$INDICES i
ON (i.RDB$RELATION NAME = r.RDB$RELATION_NAME)
WHERE r.RDB$RELATION_NAME NOT STARTING WITH 'RDB$'
GROOP BY
r.RDB$RELATION_NAME
HAVING
MIN(i.RDB$STATISTICS) MAX(i.RDB$STATISTICS);
RDB$RELATION NAME Maxl Max2
MTRANSACTION 000000000000001 18 - 1.000000000000000
MEMBER 0.0135135138407 12 - 0.01351351384073496
! ! !
ВНИМАНИЕ! Вы можете получить результат при выполнении этого запроса в Firebird 1.0.x, однако он будет некорректным.
. ! .
Агрегатное выражение может быть вложено внутрь другого агрегатного выражения, если внутренняя агрегатная функция находится на более низком уровне (контексте), что иллюстрируется предыдущим запросом.