Язык SQL и его глубина … Некоторые из вас, читатели, могут знать о возможности MySQL по подсчету различных записей с помощью агрегатной функции COUNT (). Документация MySQL гласит:
COUNT(DISTINCT
expr
,[expr
...])Возвращает счетчик количества строк с разными
expr
значениямиexpr
.
Другими словами, вы можете очень легко считать разные имена и фамилии:
1
2
|
SELECT COUNT ( DISTINCT FIRST_NAME, LAST_NAME) FROM CUSTOMERS |
Это довольно полезно, но специфично для MySQL ( хотя HSQLDB также поддерживает этот конкретный синтаксис MySQL ). Большинство других баз данных, однако, не предлагают такую функцию, даже если стандарт SQL-99 уже определил ее:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
|
6.16 < set function specification> < set function specification> ::= COUNT < left paren> < asterisk > < right paren> | < general set function> < general set function> ::= < set function type> < left paren> [ < set quantifier> ] < value expression> < right paren> < set function type> ::= < computational operation> < computational operation> ::= AVG | MAX | MIN | SUM | EVERY | ANY | SOME | COUNT < set quantifier> ::= DISTINCT | ALL |
Выше было позже объединено в 10.9 <агрегатная функция> в SQL: 2011 со множеством других типов и функций агрегатных функций. Теперь давайте посмотрим на 6.23 <выражение значения>:
01
02
03
04
05
06
07
08
09
10
11
12
|
6.23 < value expression> < value expression> ::= < numeric value expression> | < string value expression> | < datetime value expression> | < interval value expression> | < boolean value expression> | < user-defined type value expression> | < row value expression> <-- RVE! | < reference value expression> | < collection value expression> |
Интересно, что вы можете поместить выражение значения строки в некоторые из ваших агрегатных функций. Существуют дополнительные ограничения, например, вы не можете SUM()
или AVG()
. Но с COUNT()
и COUNT(DISTINCT ...)
это имеет смысл. Таким образом, в соответствии со стандартом SQL (и в соответствии с альтернативой HSQLDB и основной реализацией PostgreSQL, которая, к сожалению, на самом деле не документирована), следующий способ будет правильным способом подсчитывать разные имена и фамилии в SQL:
1
2
|
SELECT COUNT ( DISTINCT (FIRST_NAME, LAST_NAME)) FROM CUSTOMERS |
… что имеет смысл. Будьте внимательны при чтении этого. Это не функция DISTINCT()
! Это ключевое слово DISTINCT
применяемое к выражению значения строки. Смотрите некоторые предыдущие сообщения в блоге о выражениях значения строки здесь:
- Забава преобразования запроса SQL: предикаты с выражениями значения строки
- Выражение значения строки и предикат BETWEEN
- Выражение значения строки и предикат NULL
jOOQ стандартизирует различные диалекты SQL и скрывает вышеуказанное за DSL.countDistinct()
.
Когда вы не используете HSQLDB, MySQL или PostgreSQL
В других базах данных вы можете прибегнуть к ручному преобразованию SQL. Наш пример легко трансформируется:
1
2
3
4
5
|
SELECT COUNT (*) FROM ( SELECT DISTINCT FIRST_NAME, LAST_NAME FROM CUSTOMERS ) t |
Но такое преобразование запроса может оказаться сложным, если у вас есть предложения GROUP BY
или другие агрегатные функции. Будущие версии jOOQ могут сделать для вас такую трансформацию.