#sql #sql-server #date #datediff #difference
#sql #sql-сервер #Дата #datediff #разница
Вопрос:
У меня есть таблица, которая состоит из следующих данных.
Employee TimeRegister1 TimeRegister2 TimeRegister3 TimeRegister4
77 2014-04-01 11:51:43.000 2014-04-01 14:03:52.000 2014-04-01 14:17:01.000 2014-04-01 16:01:12.000
77 2014-04-03 09:48:33.000 2014-04-03 12:13:43.000 2014-04-03 12:22:27.000 2014-04-03 14:03:43.000
181 2014-04-02 08:24:34.000 2014-04-02 13:01:10.000 2014-04-02 14:30:31.000 2014-04-02 18:04:04.000
Что мне нужно, так это записать в другом столбце общее количество, рассчитанное на основе различий между каждой парой столбцов (нечетное минус четное) для каждого сотрудника / день.
В приведенном выше примере, для Employee 77 and 2014-04-01
, он должен записать в другой столбец сумму разностей между TimeRegister 2 - TimeRegister 1
, TimeRegister 4 - TimeRegister 3
.
Должно быть выведено что-то вроде этого (секунды не имеют значения, просто нужны часы / минуты):
Employee TimeRegister1 TimeRegister2 TimeRegister3 TimeRegister4 CALCULATEDCOL
77 2014-04-01 11:51:43.000 2014-04-01 14:03:52.000 2014-04-01 14:17:01.000 2014-04-01 16:01:12.000 2014-04-01 03:56:00.000
Кроме того TimeRegister
, столбцов может быть до 30 (я только что показал 4 столбца, но может быть и больше), поэтому мне нужно последовательное вычисление для каждой четной / нечетной пары, пока не закончатся столбцы.
Буду признателен за любую помощь, как я могу добиться этого в SQL. Спасибо.
Комментарии:
1. Есть ли столбец, который указывает «In» против «Out» (т. Е. В настоящее время вы предполагаете, что существует четное количество записей и направление регистра). Кроме того, «DateTime» — это действительно просто разница во времени, т. Е. Должен быть столбец с другим типом данных, например Time?
2. Привет, Стюарт, спасибо за ваш вклад. Столбец «TimeRegister1» — это столбец «IN» (первый регистр времени за день — всегда IN). Иногда возможно, что нет даже регистра времени (например, сотрудник зарегистрировался, но забыл проверить). Конечно, эти ошибки следует игнорировать. Допустим, сотрудник выписывается на обед, когда он возвращается, он забыл зарегистрироваться. Когда он проверяет в конце дня, это будет рассматриваться как РЕГИСТРАЦИЯ. Аномалии будут обработаны вручную (т. Е. Добавление забытых возвратов / исходов) и соответствующим образом пересчитаны.
3. Это действительно плохой дизайн таблицы. Похоже, что он был разработан на основе физической формы, а не путем размышления о данных. В идеале все эти значения даты и времени должны быть в одном столбце — с отдельной строкой для каждой записи. Вы могли бы приблизиться к этому, выполнив
UNPIVOT
сначала для этих данных.4. Привет, Дэмиен, в исходной таблице действительно есть значения даты и времени в одном столбце с отдельной строкой для каждой записи. Это таблица, полученная в результате операции PIVOT. Мы сделали это, чтобы передать его в программную сетку, чтобы сотрудники отдела кадров могли работать с входами и выходами в одной строке для лучшего анализа. Конечно, я могу работать с исходной таблицей, а затем СВОДИТЬ все, когда будут выполнены все вычисления. Есть мысли?
Ответ №1:
Предполагая, что представленная таблица верна (т. Е. Не 30 столбцов), вы можете сделать это, введя DATEDIFF
DateTimes, сложив различия вместе, а затем добавив их обратно к базовой дате одного из периодов времени (при условии, что все даты и даты приходятся на один и тот же день). Вы можете исключить секунды, выбрав минуты в качестве разрешения diff / add. И для обработки отсутствующих данных вам потребуется ISNULL()
или COALESCE
для каждого In / Out
сопряжения.
SELECT Employee, TimeRegister1, TimeRegister2, TimeRegister3, TimeRegister4,
DATEADD(mi, ISNULL(DATEDIFF(mi, TimeRegister1, TimeRegister2), 0)
ISNULL(DATEDIFF(mi, TimeRegister3, TimeRegister4), 0),
CAST(CAST(TimeRegister1 AS DATE) AS DATETIME))
as CALCULATEDCOL
FROM TimeRegister;
Согласно комментарию, может быть лучше разделить CALCULATEDCOL
на отдельные компоненты даты и времени, поскольку в его нынешнем CALCULATEDCOL
виде он вообще не представляет момент времени.
Если у вас действительно есть до 30 столбцов, вам нужно будет повторить вычисление для каждой пары In/Out
данных (и надеяться, что сотрудники не покидают здание чаще 15 раз в день!).
Редактировать
Чтобы сделать это из необработанной таблицы данных ввода / вывода часов, предполагая, что направление доступно (в противном случае данные практически бесполезны), и отбрасывая любые данные, в которых сотрудник не включал и не выключал последовательно, в тот же день, как насчет:
WITH cte AS
(
SELECT Employee,
TimeRegister,
Direction,
CAST(TimeRegister AS DATE) AS TheDate,
ROW_NUMBER() OVER (PARTITION BY Employee, CAST(TimeRegister AS DATE)
ORDER BY TimeRegister ASC) AS Rnk
FROM TimeRegister
)
SELECT
cur.Employee,
DATEADD(mi, SUM(DATEDIFF(mi, cur.TimeRegister, nxt.TimeRegister)),
CAST(cur.TheDate AS DATETIME)) AS CALCULATEDCOL
FROM cte cur
INNER JOIN cte nxt
ON cur.Employee = nxt.Employee
AND cur.TheDate = nxt.TheDate AND cur.Rnk 1 = nxt.Rnk
WHERE cur.Direction = 'I' AND nxt.Direction = 'O'
GROUP BY cur.Employee, cur.TheDate;