Могу ли я сделать это в функции SQL без курсора?
================================================

Я работаю над базой данных расписаний. Проще говоря, таблица TimesheetEntries имеет четыре столбца

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

Тем не менее, и именно здесь это становится непростым делом, сотрудники иногда вынуждены покидать сайт на короткие промежутки времени, и отчет должен игнорировать их (когда они покидают сайт менее чем за 2 часа).

Итак, давайте предположим, что следующие записи

Выходные данные отчета**SHOULD** быть

Есть ли способ сделать это без курсора или даже курсора, вложенного в курсор (где я сейчас нахожусь!)? Мы здесь не говорим об огромных наборах данных, и производительность не является действительно проблемой (это отчет, а не производственная система), но мне действительно не нравятся курсоры, если я могу их избежать.

Спасибо

Эдвард

 но решил проблему совершенно по-другому. При этом используется рекурсивный CTE, который, как мне кажется, требует SQL Server 2005. Он точно сообщает о результатах (я полагаю), а также сообщает количество включений, записанных в течение таймфрейма, и общее количество отключенных минут (может быть больше 120, поскольку ограничение состоит в том, что каждый период вне офиса составляет менее двух часов).

Это возвращает:

**UPDATE**

В случае, если это не ясно, MinutesOff - это только «надбавка»; время или количество времени, "съеденного"; между ClockedIn и EffectiveClockout, показанными в одной строке. Таким образом, для StaffID 5 между синхронизированными периодами времени потребовалось 129 минут, но без учета допустимого времени, поэтому MinutesOff равен 0 для обеих строк.



Возможно, вставьте его во временную таблицу, а затем используйте левое соединение, чтобы построить таблицу результатов (если они могут входить и выходить дважды только в течение дня, это будет работать, если у вас будет 3 результата, но это не так).

После этого вы можете просто получить минимальное и максимальное значения или даже получить более надежный отчет.

Вариант 2:

Если бы мне понадобилось больше времени, я бы объединил их в два быстрых запроса, но три из них будут работать, чтобы не беспокоиться о производительности.



Я уверен, что есть некоторые оптимизации, которые должны быть сделаны.



 что вы можете сделать это довольно легко, просто вернувшись к себе и сыграв одноразовый матч. Ниже приведена не полная реализация, а скорее подтверждение концепции:

Идея в том, что у вас есть исходная таблица расписаний.`tse1`, а затем вы делаете`left join` к той же таблице расписания, с псевдонимом`tse2` и соответствующие строки, когда`staffID` то же самое и`tse2.ID` самое высокое значение идентификатора, которое по-прежнему меньше, чем`tse1.ID`, Это явно плохая форма - вы, вероятно, хотите использовать`ROW_NUMBER()` для этого сравнения ID, разделены и упорядочены`StaffID` и ваш`ClockedIn`/`ClockedOut` значения, так как времена могли быть введены в хронологическом порядке.

На этом этапе строка из соединенных таблиц теперь содержит данные о времени из текущей записи расписания, а также предыдущую запись. Это означает, что мы можем сделать сравнение между`ClockedIn`/`ClockedOut` значения для последовательных записей времени ... и использования`DATEDIFF()`мы можем выяснить, сколько времени пользователь провел в промежутке между`Clockedout` и более свежий`ClockedIn` ценности. Я использовал`OUTER APPLY` просто потому, что это делает код чище, но вы, вероятно, могли бы упаковать его в подзапрос.

Как только мы сделаем`DATEDIFF()`тривиально находить случаи, когда индивидуум`BreakTime` не превышает 120-минутного барьера и удаляет эти записи расписания, оставляя только значимые строки расписания сотрудника, которые будут использоваться в ваших последующих отчетах.



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