Статьи

Подсчет различных записей в SQL

Язык 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 применяемое к выражению значения строки. Смотрите некоторые предыдущие сообщения в блоге о выражениях значения строки здесь:

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 могут сделать для вас такую ​​трансформацию.

Справка: Подсчет отдельных записей в SQL от нашего партнера по JCG Лукаса Эдера из блога JAVA, SQL и JOOQ .