Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / Firebird, InterBase [игнор отключен] [закрыт для гостей] / Посчитать время присутствия по паре строк ВХОД и ВЫХОД / 23 сообщений из 23, страница 1 из 1
28.11.2013, 10:05:56
    #38481169
sss71
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Посчитать время присутствия по паре строк ВХОД и ВЫХОД
Здравствуйте!

Вот такой вопрос образовался:
Имеется таблица REG_EVENTS, в которой содержатся события входа и выхода.
Идентификатор человека, дата и время события и, последнее, тип события
IDENTIFIER, DATE_EV, TIME_EV, AREAS_ID
Первые три очевидны, последнее - если =1, то это выход, иначе вход.
Требуется найти продолжительность присутствия для каждого случая, т.е. выход минус вход.
В таблице идут строки последоватеьно: ВХОД-ВЫХОД-ВХОД-...
Единственное, на что меня хватило, вот такой селект:

select a.identifier, a.date_ev, min(time_ev), max(time_ev) from REG_EVENTS a group by a.IDENTIFIER, a.date_ev

т.е. игнорируем промежуточные входы-выходы и в пределах одного дня всё замечательно.
Но желательно и промежуточные посчитать, но самое главное, вход может быть сегодня, а выход завтра, и вот тут группировка по дате не прокатывает.
В фоксе подобное решается перебором строк, а вот как это сделать SQL-запросом, тут я не знаю.
Посоветуйте, в какую сторону копать?

С уважением, Сергей.
...
Рейтинг: 0 / 0
28.11.2013, 10:23:28
    #38481202
wadman
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Посчитать время присутствия по паре строк ВХОД и ВЫХОД
sss71, в сторону процедур, конечно же
...
Рейтинг: 0 / 0
28.11.2013, 10:24:11
    #38481204
wadman
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Посчитать время присутствия по паре строк ВХОД и ВЫХОД
sss71DATE_EV, TIME_EV
Кто такое придумал? Почему не timestamp?
...
Рейтинг: 0 / 0
28.11.2013, 10:28:11
    #38481212
miwaonline
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Посчитать время присутствия по паре строк ВХОД и ВЫХОД
sss71,

Я бы добавил поле "длительность" и вычислял его в триггере при заполнении поля "время выхода", а в запросах суммировал бы длительность. Правда, если есть варианты типа "зашел сегодня, а вышел через год" и посчитать надо только то, что сегодня, прямое суммирование не проканает. А еще бы учесть, что можно (ошибочно) зайти сегодня, а выйти послезавтра и тогда надо думать, как вычислить (и надо ли) завтра.

Это все я к тому, что маловато входных данных.
...
Рейтинг: 0 / 0
28.11.2013, 10:31:06
    #38481219
miwaonline
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Посчитать время присутствия по паре строк ВХОД и ВЫХОД
miwaonline,

Тьфутыблин, показалось, что вход и выход содержатся в одной записи.

Но все равно, одним селектом такое разве что Таблоид сделает, если у него будет «час і натхнення»© (время и вдохновение). :)
...
Рейтинг: 0 / 0
28.11.2013, 10:34:37
    #38481223
wadman
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Посчитать время присутствия по паре строк ВХОД и ВЫХОД
miwaonlineНо все равно, одним селектом
Как он осилит, когда один зашел, а вышли - два? А десять? У нас на всех дверях и по одному пропуску может хоть цех выйти. И только на проходной стоит крутилка и только там каждый проходит отдельно.
...
Рейтинг: 0 / 0
28.11.2013, 11:18:02
    #38481322
Fr0sT-Brutal
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Посчитать время присутствия по паре строк ВХОД и ВЫХОД
И то, все эти крутилки имеют вероятность глюкнуть, сломаться. Надо сразу закладываться на то, что будут встречаться "рваные" данные. Если у вас нет круглосуточных фахт, я бы посоветовал при отсутствии факта ухода/прихода принудительно ставить время ухода/прихода полуночью (либо официальным временем окончания/начала рабочего дня). Ну и заодно добавить признак, что это время не соответствует реальности (для отчета о багах и в конфликтных ситуациях).
соответственно при такой логике одним запросом не обойтись. Ну а с ХП можно и перебор сделать
...
Рейтинг: 0 / 0
28.11.2013, 11:28:11
    #38481353
TurutaSergey
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Посчитать время присутствия по паре строк ВХОД и ВЫХОД
wadmansss71DATE_EV, TIME_EV
Кто такое придумал? Почему не timestamp?

Согласен.
Из стартпоста не понятно какая СУБД,
но я начал бы с того, что объеденил два поля DATE_EV, TIME_EV в одно DATE_TIME_EV.

в итоге получаем следующее:
IDENTIFIER, DATE_TIME_EV, AREAS_ID
Не претендую на самый быстрый вариант. И одним select тут не обойтись.

если вложенные select в вашей СУБД прокатят, то ход мыслей следующий:

сканируем дважды таблицу для входов (A) и для выходов (B).

select A.IDENTIFIER, A.DATE_TIME_EV as TIME_A, B.DATE_TIME_EV as TIME_B

from
(select IDENTIFIER, DATE_TIME_EV where AREAS_ID != 1) A, -- входы
(select IDENTIFIER, DATE_TIME_EV where AREAS_ID = 1) B -- выходы
where (A.IDENTIFIER = B.IDENTIFIER)
and (B.DATE_TIME_EV > A.DATE_TIME_EV) -- в этом месте отбираем только те выходы, которые были после входа
group by A.IDENTIFIER
having (B.DATE_TIME_EV - A.DATE_TIME_EV) = MIN (B.DATE_TIME_EV - A.DATE_TIME_EV) -- в этом месте отбираем те выходы, которые со входом имеют минимальную разницу во времени.

на движке не проверял. Может, рабочий запрос будет выглядеть немного по-другому. Но общая идея такова.
...
Рейтинг: 0 / 0
28.11.2013, 11:55:03
    #38481420
TurutaSergey
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Посчитать время присутствия по паре строк ВХОД и ВЫХОД
так лучше будет:

select A.IDENTIFIER, A.DATE_TIME_EV as TIME_A,
MIN(B.DATE_TIME_EV) as TIME_B -- в этом месте отбираем те выходы, которые следуют сразу после входа.

from
(select IDENTIFIER, DATE_TIME_EV where AREAS_ID != 1) A, -- входы
(select IDENTIFIER, DATE_TIME_EV where AREAS_ID = 1) B -- выходы
where (A.IDENTIFIER = B.IDENTIFIER)
and (B.DATE_TIME_EV > A.DATE_TIME_EV) -- в этом месте отбираем только те выходы, которые были после входа
group by A.IDENTIFIER, A.DATE_TIME_EV

даже заработать сразу должен, после того как DATE_EV, TIME_EV будут объедены в одно поле DATE_TIME_EV.
...
Рейтинг: 0 / 0
28.11.2013, 12:15:55
    #38481471
TurutaSergey
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Посчитать время присутствия по паре строк ВХОД и ВЫХОД
Fr0sT-BrutalИ то, все эти крутилки имеют вероятность глюкнуть, сломаться. Надо сразу закладываться на то, что будут встречаться "рваные" данные. Если у вас нет круглосуточных фахт, я бы посоветовал при отсутствии факта ухода/прихода принудительно ставить время ухода/прихода полуночью (либо официальным временем окончания/начала рабочего дня). Ну и заодно добавить признак, что это время не соответствует реальности (для отчета о багах и в конфликтных ситуациях).
соответственно при такой логике одним запросом не обойтись. Ну а с ХП можно и перебор сделать

Предлагаю рассмотреть пример.

рабочий день с 9:00 до 18:00
перерыв с 13:00 до 14:00

1. Законопослушный вариант:
вход 8:55
выход 13:05
вход 13:55
выход 18:05

Итог: первый вх-вых (4:10) + второй вх-вых (4:10) = 8:20 время в офисе

2. Вариант, в котором сотрудник "забыл" отметить выход на перерыв:
вход 8:55
выход: отсутствует
вход 13:55
выход 18:05

Итог: первый вх-вых (9:10) + второй вх-вых (4:10) = 13:20 (!) время в офисе при 8-ми часовом дне
поэтому, при отсутствующих данных два входа или два выхода подряд нужно принимать решение, что с этим делать.
возможно, ввести "презумпцию виновности": если входа подряд, то первый вход не учитывать. Учитывать только второй.

тогда у "забывчивых" сотрудников будет стимул не забывать отмечаться:
Итог для "забывчивых": первый вх-вых (0:00) + второй вх-вых (4:10) = 4:10 тогда это будет правильно.
...
Рейтинг: 0 / 0
28.11.2013, 14:38:40
    #38481816
sss71
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Посчитать время присутствия по паре строк ВХОД и ВЫХОД
Некоторое время интернет не работал, потому отвечу всем в одном письме:

1. База существует как есть и заполняется не мной. Никаких полей я туда добавлять не могу. Я лишь хочу получать выборки из неё, отличные от стандартного функционала.
2. Ходить всем по одному пропуску не дадут суровые дяди, варианты с двумя входами и одним выходом исходной программой предусмотрены и соответственно помечаются. Я не стал на них заострять внимание, т.к. сам отфильтрую без проблем. Варианты с отключением света и т.п. тоже имеются в виду. Они у меня тупо записаны на бумажку, и при анализе выборки учитывается, что такому-то числу верить нельзя.
3. Процедурами не владею, но
4. вот идея с двумя селектами из одной таблицы в качестве источников мне понравилась. Буду копать в эту сторону.


Спасибо всем ответившим!
...
Рейтинг: 0 / 0
28.11.2013, 14:43:02
    #38481826
sss71
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Посчитать время присутствия по паре строк ВХОД и ВЫХОД
СУБД - Firbird SQL 2.5
...
Рейтинг: 0 / 0
28.11.2013, 14:50:05
    #38481847
Dimitry Sibiryakov
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Посчитать время присутствия по паре строк ВХОД и ВЫХОД
sss71СУБД - Firbird SQL 2.5
Эх, а я только собрался посоветовать функцию LAG()...
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
28.11.2013, 17:18:38
    #38482205
Таблоид
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Посчитать время присутствия по паре строк ВХОД и ВЫХОД
sss71желательно и промежуточные посчитать, но самое главное, вход может быть сегодня, а выход завтра DDL:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
recreate table t(   dts timestamp primary key using index t_dts_idx,
                    evt smallint,
                    constraint valid_evt check( evt in(1,2) )
                );
commit;

delete from t;
commit;
-- согласующийся вход-выход, "дневная смена":
insert into t values('15.11.2013 09:00:29', 1);
insert into t values('15.11.2013 17:58:31',2);

-- еще один согласующийся вход-выход, "ночная смена":
insert into t values('16.11.2013 21:19:24', 1);
insert into t values('16.11.2013 06:03:21',2);

-- только входы (бардак на проходной-1):
insert into t values('17.11.2013 09:10:10', 1);
insert into t values('17.11.2013 14:02:32', 1);
insert into t values('18.11.2013 09:01:11', 1);

-- только выходы (бардак на проходной-2):
insert into t values('19.11.2013 13:00:22',2);
insert into t values('19.11.2013 17:57:29',2);
insert into t values('20.11.2013 13:01:27',2);
insert into t values('20.11.2013 18:01:19',2);

-- множество согласованных входов-выходов за 1 день:
insert into t values('21.11.2013 08:54:55', 1);
insert into t values('21.11.2013 11:23:22',2);
insert into t values('21.11.2013 12:01:44', 1);
insert into t values('21.11.2013 13:02:22',2);
insert into t values('21.11.2013 14:06:26', 1);
insert into t values('21.11.2013 18:00:25',2);

-- разница между входом и выходом свыше 1 календарного дня
-- (т.е. вход "позавчера", а выход - "сегодня"), считается ошибкой:
insert into t values('22.11.2013 09:07:17', 1);
insert into t values('24.11.2013 18:00:21',2);
commit;
Query: (не сгруппированный; null в графе `was_here` означает ошибку в этом дне)
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
with
c as(
select dts tc,evt ec,(select first 1 cast(x.dts as char(25))||cast(x.evt as char(1)) tx from t x where x.dts>t.dts) tx
from t
)
,d as(
select tc,ec,cast(left(tx,25) as timestamp) tx,cast(right(tx,1) as smallint) ex
from c
)
select tc,tx,ec,ex,  iif(ec < ex and cast(tx as date)-cast(tc as date)<=1, datediff(minute from tc to tx), null) was_here
from d
where ec=1
order by tc;

Выборку с учетом пользователей сделаете сами.
ЗЫ. Через процедуру будет быстрее, т.к. таблица будет пройдена только один раз.
...
Рейтинг: 0 / 0
28.11.2013, 17:31:33
    #38482228
Таблоид
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Посчитать время присутствия по паре строк ВХОД и ВЫХОД
В трёшке с оконными ф-циями всё проще и короче:
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
with
d as(
    select  dts tc
            ,evt ec
            ,lead(dts)over(order by dts) tx
            ,lead(evt)over(order by dts) ex
    from t
)
select tc,tx,ec,ex,  iif(ec < ex and cast(tx as date)-cast(tc as date)<=1, datediff(minute from tc to tx), null) was_here
from d
where ec=1

Но для поиска следующей строки в порядке возрастания даты не задействован индекс t_dts_idx, как того хотелось бы. Поэтому что там будет на большом числе строк - еще вопрос.
...
Рейтинг: 0 / 0
28.11.2013, 17:33:46
    #38482231
miwaonline
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Посчитать время присутствия по паре строк ВХОД и ВЫХОД
miwaonlinemiwaonline,
Но все равно, одним селектом такое разве что Таблоид сделает, если у него будет «час і натхнення»© (время и вдохновение). :)

wadmanmiwaonlineНо все равно, одним селектом
Как он осилит, когда один зашел, а вышли - два? А десять?

Таблоид Query: (не сгруппированный; null в графе `was_here` означает ошибку в этом дне)

Выборку с учетом пользователей сделаете сами.
ЗЫ. Через процедуру будет быстрее, т.к. таблица будет пройдена только один раз.

Я знал
...
Рейтинг: 0 / 0
28.11.2013, 17:36:44
    #38482239
Таблоид
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Посчитать время присутствия по паре строк ВХОД и ВЫХОД
miwaonlineЯ знал а что тут сложного ?.. %-)
Смотрим, "что там дальше записано было", и применяем простые проверки.
ТС, возможно, еще что-то там недоговорил про их труд и быт, но это уже пусть сам дорёшивает.
...
Рейтинг: 0 / 0
28.11.2013, 18:10:52
    #38482291
Таблоид
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Посчитать время присутствия по паре строк ВХОД и ВЫХОД
Таблоид
Код: plaintext
(select first 1 cast(x.dts as char(25))||cast(x.evt as char(1)) tx from t x where x.dts>t.dts)
ooops! order by забыл, сорри. Вот так надо:
Код: plaintext
1.
(select cast(x.dts as char(25))||cast(x.evt as char(1)) tx from t x where x.dts>t.dts  order by x.dts rows 1 )
...
Рейтинг: 0 / 0
28.11.2013, 18:31:17
    #38482335
Евгений Болтик
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Посчитать время присутствия по паре строк ВХОД и ВЫХОД
sss71Здравствуйте!
Идентификатор человека, дата и время события и, последнее, тип события
IDENTIFIER, DATE_EV, TIME_EV, AREAS_ID
Первые три очевидны, последнее - если =1, то это выход, иначе вход.
С уважением, Сергей.

А если сервер или программа упадет как отследишь? Выход некуда/некому записать. Может лучше каждые х секунд еще и говорить работает.
1 - вошел
2 - работает т.к х секунд оповещают
3 - вышел
4 - аварийный выход (это состояние тоже отслеживается) к примеру у меня более 2 минут нет сообщений значит отвалился.

А дальше, тут варианты предлагали, зашел и не вышел до завтра. Это тоже решается. Есть функции видовые "Простаивает ОС".
...
Рейтинг: 0 / 0
28.11.2013, 18:41:59
    #38482357
Kotъ-Begemotъ
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Посчитать время присутствия по паре строк ВХОД и ВЫХОД
Я для себя этот вопрос решил, хранением в одной строке и времени входа и выхода. На "сессию" получается ID и с этим пишется время входа, и при выходе - выхода. А чтобы, при каком-то сбое время выхода не осталось незаполненным, оно каждые несколько минут (и сразу при входе) заполняется текущим TIMESTAMP и признаком "автоматической" записи. А когда реально юзер выходит, ставится время выхода, и снимается флаг "автозаписи".
Зато считается всё потом элементарным запросом.
...
Рейтинг: 0 / 0
28.11.2013, 18:46:51
    #38482369
Таблоид
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Посчитать время присутствия по паре строк ВХОД и ВЫХОД
ТаблоидВ трёшке с оконными ф-циями всё проще и короче:<...>
Но для поиска следующей строки в порядке возрастания даты не задействован индекс t_dts_idx, как того хотелось бы. Поэтому что там будет на большом числе строк - еще вопрос .Уже нет вопроса.
По кр мере, для таблицы с 15 лямами строк, в которую добавлялись случайные int-числа:
sample
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
SQL> select count(*) from t;

             15813251

SQL> select * from t rows 10;

      384138
      633262
      582286
      263649
      282770
      188050
      623496
      499282
       19429
      134205
- оконная функция lead()over(order by x) явно рулит по сравнению со скалярным подзапросом:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
SQL> set stat on;
SQL> set explain on;
SQL> select count(*) from (select tc.x,(select first 1 x from t tx where tx.x>tc.x order by tx.x) tx from t tc);

Select Expression
    -> Singularity Check
        -> First N Records
            -> Filter
                -> Table "TX" Access By ID
                    -> Index "T_X" Scan
Select Expression
    -> Aggregate
        -> Union
            -> Table "TC" Full Scan

             15813251

Current memory = 2450745104
Delta memory = 544752
Max memory = 2450796560
Elapsed time= 562.68 sec
Cpu = 0.05 sec
Buffers = 524288
Reads = 215467
Writes = 0
Fetches = 924779969

SQL> select count(*) from (select tc.x,lead(x)over(order by x) tx from t tc);

Select Expression
    -> Aggregate
        -> Window
            -> Record Buffer
                -> Table "TC" Full Scan

             15813251

Current memory = 2450734048
Delta memory = -11056
Max memory = 2536880256
Elapsed time= 122.29 sec
Cpu = 0.00 sec
Buffers = 524288
Reads = 0
Writes = 0
Fetches = 32017389
SQL> set explain off;
SQL> set stat off;
(проверял на SS, но в другом окне идёт еще один тест; впрочем, вряд ли и на "чистом" окружении будет по-другому).
...
Рейтинг: 0 / 0
28.11.2013, 18:53:54
    #38482377
TurutaSergey
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Посчитать время присутствия по паре строк ВХОД и ВЫХОД
Kotъ-BegemotъЯ для себя этот вопрос решил, хранением в одной строке и времени входа и выхода. На "сессию" получается ID и с этим пишется время входа, и при выходе - выхода. А чтобы, при каком-то сбое время выхода не осталось незаполненным, оно каждые несколько минут (и сразу при входе) заполняется текущим TIMESTAMP и признаком "автоматической" записи. А когда реально юзер выходит, ставится время выхода, и снимается флаг "автозаписи".
Зато считается всё потом элементарным запросом.

Мне нравится! Неплохой выход из ситуации. Дешиво и сердито.
А разгильдяйство человеческого фактора можно потом логикой победить.
...
Рейтинг: 0 / 0
29.11.2013, 07:57:50
    #38482816
sss71
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Посчитать время присутствия по паре строк ВХОД и ВЫХОД
Насчет входа и выхода в одной строке - не потянет. Если даже не считать того, что система уже построена и написана, то вход может быть в одно место, а выход из другого, или вход во внешние ворота, потом вход во внутренние. Тот самый признак areas_id = 1 на самом деле означает 1 - внешняя территория, а внутренних может быть много. Поэтому 1 - выход, а <>1 - вход, неважно куда.
...
Рейтинг: 0 / 0
Форумы / Firebird, InterBase [игнор отключен] [закрыт для гостей] / Посчитать время присутствия по паре строк ВХОД и ВЫХОД / 23 сообщений из 23, страница 1 из 1
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]