Подсчитайте равные части даты в столбце отметки времени ПО группам по указанному столбцу - PullRequest
0 голосов
/ 03 июля 2018

Я хотел бы посчитать повторяющиеся значения даты. Я уже знаю, что мое поле «КОГДА» является меткой времени, поэтому я должен привести его к типу даты.

мой фактический запрос выглядит так:

SELECT 
    u.USERNAME,  
    r."WHEN",
    r.UPDATEINOUT,
    case (r.UPDATEINOUT) when 0 then  0 when 1 then 1 else r.INOUT end INOUT
FROM 
    ATTENDANT r 
LEFT JOIN  
    USERS u ON r.USERID = u.ID 
where 
    u.USERNAME = 'rk' and (r.UPDATEINOUT = 1 or r.UPDATEINOUT = 0 or r.UPDATEINOUT is null)
group by
    r."WHEN",
    INOUT,
    u.USERNAME,
    r.UPDATEINOUT
order by 
    r."WHEN"

И вот результат:

Username     WHEN             UPDATEINOUT  INOUT

rk  09.04.2018, 14:59:45.000    [null]  0
rk  09.04.2018, 14:59:51.000    [null]  1
rk  11.04.2018, 08:31:02.000    [null]  0
rk  11.04.2018, 12:06:52.000    [null]  1
rk  11.04.2018, 12:10:29.000    [null]  0
rk  11.04.2018, 12:23:09.000    [null]  1
rk  11.04.2018, 12:43:47.000    [null]  0
rk  11.04.2018, 17:07:40.000    [null]  1

Теперь я бы хотел посчитать повторяющиеся даты, результат должен выглядеть следующим образом:

Username     WHEN             UPDATEINOUT  INOUT  Count

    rk  09.04.2018, 14:59:45.000    [null]  0       2
    rk  09.04.2018, 14:59:51.000    [null]  1       2
    rk  11.04.2018, 08:31:02.000    [null]  0       6
    rk  11.04.2018, 12:06:52.000    [null]  1       6
    rk  11.04.2018, 12:10:29.000    [null]  0       6
    rk  11.04.2018, 12:23:09.000    [null]  1       6
    rk  11.04.2018, 12:43:47.000    [null]  0       6
    rk  11.04.2018, 17:07:40.000    [null]  1       6

Когда я добавляю

count(cast(r."WHEN" as date))

тогда это показывает мне только один.

Ответы [ 3 ]

0 голосов
/ 03 июля 2018

Я думаю, вам нужно subquery:

SELECT  u.USERNAME, r."WHEN", r.UPDATEINOUT,
        case (r.UPDATEINOUT) when 0 then  0 when 1 then 1 else r.INOUT end INOUT,
        (SELECT COUNT(*) 
         FROM ATTENDANT r1 
         WHERE cast(r1."WHEN" as date)) = cast(r."WHEN" as date)
        ) as Count
FROM ATTENDANT r LEFT JOIN  
     USERS u 
     ON r.USERID = u.ID 
WHERE u.USERNAME = 'rk' AND 
    (r.UPDATEINOUT = 1 or r.UPDATEINOUT = 0 or r.UPDATEINOUT is null)
GROUP BY r."WHEN", INOUT, u.USERNAME, r.UPDATEINOUT
ORDER BY r."WHEN";
0 голосов
/ 03 июля 2018

Кажется, есть ответы, предлагающие "что делать", но не пытающиеся объяснить, почему результаты похожи на то, что они есть. Что происходит. Похоже, что начинающему по теме дается рыба, а не удочка.

Когда я добавляю 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» может отличаться.

Однако ....

  1. Я думаю, что не каждый сервер SQL поддерживает выражения в предложении group by.
  2. Если не существует index, созданного именно этим выражением, серверу придется проделать большую дополнительную работу, возможно, прибегая к естественному сканированию и группированию временных файлов, что сделает запрос тяжелым и медленным.
  3. И, конечно, вы должны изменить список столбцов соответственно.

.

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.

0 голосов
/ 03 июля 2018

Вы можете перейти на Firebird 3.0 и использовать оконные функции.

В качестве альтернативы, вы можете использовать CTE

with t as ( < your query here > )
select t.*, tw.cnt
from t join
     (select cast("WHEN" as date) as wdate, count(*) as cnt
      from t
      group by cast("WHEN" as date)
     ) tw
     on cast(t."WHEN" as date) = tw.wdate;
...