Кажется, есть ответы, предлагающие "что делать", но не пытающиеся объяснить, почему результаты похожи на то, что они есть. Что происходит.
Похоже, что начинающему по теме дается рыба, а не удочка.
Когда я добавляю count(cast(r."WHEN" as date))
, он показывает мне только один.
Это немного смешно. Эта строка показывает неправильное представление новичка между естественным человеческим языком, таким как английский, и математическими наборами языков, такими как SQL.
R.Kut читает эту добавленную строку как «я хочу count
, сколько [различных] значений given expression
существует».
Но это не то, что на самом деле означает эта команда в SQL. В SQL это означает, что «я хочу count
сколько строк там, где given expression
не равно нулю».
И, таким образом, между count(cast(r."WHEN" as date))
и count(r."WHEN")
фактически нет НИКАКОЙ РАЗНИЦЫ - эти два параметра-выражения являются либо NULL
, либо обоими NOT NULL
. Следовательно, значение count
этих одинаково обнуляемых параметров также равно.
Сама попытка урезать значение параметра агрегатной функции, например, если оно может изменить обнуляемость, является ошибочным. Я тоже был там. Требуется время, чтобы привыкнуть, что на самом деле означают агрегаты по математическим наборам, и что вы не читаете по-английски, когда читаете SQL.
Честно говоря, вы могли бы просто сделать count (1)
, удалив здесь не только тип, но и сам столбец - он все равно останется тем же, поскольку это строки, а не значения, которые просят подсчитать. Если есть строки, где "WHEN" IS NULL
- это будет учитываться как group by
, но не count
. После вы читаете и продумываете следующий раздел, возвращайтесь и играйте с http://sqlfiddle.com/#!9/ee09a/7
Теперь есть еще один параметр для функции count
, который я как бы упомянул выше. Это тот «отличный» параметр.
Примечание: можно сказать, что distinct
является ключевым словом языка SQL, а не параметром для функции, но де-факто, а не де-юре, оно меняет способ работы функции, поэтому в моем восприятии это параметр, таким необычным способом SQL часто параметры передаются функциям. Или, как еще один способ рассуждать об этом, можно увидеть часть имени функции, если представить, что у нас есть две функции на выбор, count
и count-distinct
.
Итак, автор темы мог бы добавить count(distinct cast(r."WHEN" as date))
вместо этого и ...
.... и видите, что ничего не изменилось. Поскольку в этот раз он действительно сказал бы серверу подсчитывать строки со значениями, отличными от NULL (всегда только не NULL!) И distinct
- счет идет в группе .
А что это за группы?
group by
r."WHEN",
INOUT,
u.USERNAME,
r.UPDATEINOUT
Видите, во всех группах есть строки с разными значениями времени и даты "КОГДА". И другие колонки тоже, но я не фокусируюсь на них. Дело в том, что в каждой группе и время, и часть даты «КОГДА» остаются неизменными. И «быть тем же самым» означает «есть одно distinct
значение, повторяемое снова и снова». И если есть только одно distinct
значение времени и даты, то уменьшенные значения only-time или only-date будут иметь одинаковые значения (уменьшение значения может привести только к ранее различным значениям, но не сделать ранее равным значения теперь разные).
Конечно, в других ситуациях, когда подсчет идет по столбцам, не включенным в группу (или когда предложение group by
вообще отсутствует), результат может отличаться. Там count(distinct ...)
может делать то, что ожидает от него автор темы.
http://sqlfiddle.com/#!9/0d65bf/7 - пример.
Однако нужно помнить:
- это происходит за счет дополнительной работы по сортировке и группировке, выполняемой сервером, что может сделать запрос медленным или потреблять много памяти
- все равно он будет работать внутри группы (тогда только группы начнут содержать разные значения для
count
ed столбцов). - .... просто иногда группа представляет собой полный набор результатов запроса (самый простой вариант - всю таблицу), если программист не установил ее как отличное, добавив выражение
group by
: -D
Код примера, связанный выше:
create table X(a integer, b integer);
insert into X values (1,1);
insert into X values (1,2);
insert into X values (1,2);
commit;
select count(distinct b) from x group by a
-- Result: 1 row: 2
-- or if the whole table is the group
select count(distinct b) from x
-- Result: 1 row: 2
-- but if the group includes the counted column
-- then every group would contain EXACTLY ONE
-- row with a not-null distinct value
select count(distinct b) from x group by b
-- Result: 2 rows: 1 and 1
Здесь мы подошли к еще одной модификации игрушки.
group by
cast(r."WHEN" as date), -- <====
INOUT,
u.USERNAME,
r.UPDATEINOUT
Теперь, на этот раз мы говорим серверу собрать группы, в которых только часть «date» в «WHEN» одинакова, а часть «time» может отличаться.
Однако ....
- Я думаю, что не каждый сервер SQL поддерживает выражения в предложении
group by
.
- Если не существует
index
, созданного именно этим выражением, серверу придется проделать большую дополнительную работу, возможно, прибегая к естественному сканированию и группированию временных файлов, что сделает запрос тяжелым и медленным.
- И, конечно, вы должны изменить список столбцов соответственно.
.
SELECT
u.USERNAME,
cast(r."WHEN" as date), -- <=== no more raw r."WHEN"
r.UPDATEINOUT,
Потому что, ну, вы просто не можете иметь «Одно истинное значение» для WHEN
в строке, если вы явно попросили сервер сгруппировать его различные значения.
Здесь вы можете прийти к выводу, что не существует простого и простого способа объединить как группы, так и общие группы. Или, иначе говоря, иметь два разных набора group by
в одном запросе (я не хочу упоминать здесь UNION
, ладно?).
Вам потребуется ОДИН набор критериев group by
для подсчета строк с одной и той же частью даты (но, возможно, с другой частью времени), и, тем не менее, ДРУГОЙ group by
критерий выбора и рендеринга групп, различающихся как по дате, так и по времени.
В простом и простом SQL 1999 это означает, что вам придется сделать ДВА select
s, чтобы обе группы так или иначе сформировались, и здесь вступает в действие ответ Йогеша и Гордона.
Как Гордон упоминал в пост-99 SQL, появились оконные функции, которые могут позволить вам иметь эти наборы критериев в одном select
, но они все равно недоступны в Firebird 2.x.