Вот ХП, которые вы можете попробовать
CREATE PROCEDURE usp_GetTimes @StartDate DATETIME, @EndDate DATETIME = NULL
AS
BEGIN
--Make sure that only 31 days of data is used otherwise the temp table will be too big
IF @EndDate IS NULL OR DATEDIFF(dd, @StartDate, @EndDate) > 31
SET @EndDate = DATEADD(dd, 31, @StartDate)
SELECT UserID, CONVERT(DATETIME, FLOOR(CONVERT(FLOAT, DateTimeIn))) ForDate, DateTimeIn, DateTimeOut
INTO #Times
FROM
(
SELECT DISTINCT MIN(a.DATED) OVER (PARTITION BY a.USERNAME, CONVERT(DATETIME, FLOOR(CONVERT(FLOAT, DATED)))) DateTimeIn,
MAX(a.DATED) OVER (PARTITION BY a.USERNAME, CONVERT(DATETIME, FLOOR(CONVERT(FLOAT, DATED)))) DateTimeOut,
USERNAME AS UserID
FROM TAB_CARDENTRY a
WHERE DATED BETWEEN @StartDate and @EndDate + 1
) a
SELECT DISTINCT ForDate INTO #Dates FROM #Times
--Select * from #Times order by 1
--Select * from #Dates
DECLARE @SQLstring VARCHAR(MAX)
SET @SQLstring = 'CREATE TABLE ##Test (UserID varchar(10), '
DECLARE @ForDate DATETIME
WHILE 0 < (SELECT COUNT(*) FROM #Dates)
BEGIN
SET ROWCOUNT 1
SELECT @ForDate = ForDate FROM #Dates order by ForDate
SET ROWCOUNT 0
SET @SQLstring = @SQLstring + '[Entry ' + CONVERT(VARCHAR(12), @ForDate, 106) + '] datetime, [Exit ' + CONVERT(VARCHAR(12), @ForDate, 106) + '] datetime,' + CHAR(13) + CHAR(10)
DELETE #Dates WHERE ForDate = @ForDate
END
SET @SQLstring = SUBSTRING(@SQLSTRING, 1, LEN(@SQLSTRING) - 3) + ')'
EXEC (@SQLstring)
CREATE INDEX idx1 on ##Test(UserID)
DECLARE @UserID VARCHAR(10),
@DateIn DATETIME,
@DateOut DATETIME
WHILE 0 < (SELECT COUNT(*) FROM #Times)
BEGIN
SET ROWCOUNT 1
SELECT @UserID = UserID, @DateIn = DateTimeIn, @DateOut = DateTimeOut, @ForDate = ForDate from #Times
SET ROWCOUNT 0
SET @SQLString = 'IF NOT EXISTS(SELECT 1 FROM ##Test WHERE UserID = ''' + @UserID + ''')' + CHAR(13) + CHAR(10) +
' INSERT ##Test (UserID, [Entry ' + CONVERT(VARCHAR(12), @ForDate, 106) + '], [Exit ' + CONVERT(VARCHAR(12), @ForDate, 106) + ']) ' +
' SELECT ''' + @UserID + ''', ''' + CONVERT(VARCHAR(20), @DateIn, 113) + ''', ''' + CONVERT(VARCHAR(20), @DateOut, 113) + '''' + CHAR(13) + CHAR(10) +
'ELSE' + CHAR(13) + CHAR(10) +
' UPDATE ##Test SET [Entry ' + CONVERT(VARCHAR(12), @ForDate, 106) + '] = ''' + CONVERT(VARCHAR(20), @DateIn, 113) + ''', ' + CHAR(13) + CHAR(10) +
' [Exit ' + CONVERT(VARCHAR(12), @ForDate, 106) + '] = ''' + CONVERT(VARCHAR(20), @DateOut, 113) + ''' WHERE UserID = ''' + @UserID + ''''
EXEC (@SQLstring)
DELETE #Times WHERE UserID = @UserID AND ForDate = @ForDate
END
SELECT * FROM ##Test ORDER BY 1
DROP TABLE ##Test
END
EDIT
Я посмотрел на запрос снова, и вы, возможно, не так, как выход, так что вы можете изменить часть SP выглядеть следующим образом:
Та часть, которая создает временную таблицу
WHILE 0 < (SELECT COUNT(*) FROM #Dates)
BEGIN
SET ROWCOUNT 1
SELECT @ForDate = ForDate FROM #Dates order by ForDate
SET ROWCOUNT 0
SET @SQLstring = @SQLstring + '[Entry ' + CONVERT(VARCHAR(12), @ForDate, 106) + '] varchar(20), [Exit ' + CONVERT(VARCHAR(12), @ForDate, 106) + '] varchar(20),' + CHAR(13) + CHAR(10)
DELETE #Dates WHERE ForDate = @ForDate
END
И та часть, которая вставляет данные в таблицу
WHILE 0 < (SELECT COUNT(*) FROM #Times)
BEGIN
SET ROWCOUNT 1
SELECT @UserID = UserID, @DateIn = DateTimeIn, @DateOut = DateTimeOut, @ForDate = ForDate from #Times
SET ROWCOUNT 0
SET @SQLString = 'IF NOT EXISTS(SELECT 1 FROM ##Test WHERE UserID = ''' + @UserID + ''')' + CHAR(13) + CHAR(10) +
' INSERT ##Test (UserID, [Entry ' + CONVERT(VARCHAR(12), @ForDate, 106) + '], [Exit ' + CONVERT(VARCHAR(12), @ForDate, 106) + ']) ' +
' SELECT ''' + @UserID + ''', ''' + CONVERT(VARCHAR(20), ISNULL(@DateIn, '''OFF''', 108) + ''', ''' + CONVERT(VARCHAR(20), ISNULL(@DateOut, '''OFF'''), 108) + '''' + CHAR(13) + CHAR(10) +
'ELSE' + CHAR(13) + CHAR(10) +
' UPDATE ##Test SET [Entry ' + CONVERT(VARCHAR(12), @ForDate, 106) + '] = ''' + CONVERT(VARCHAR(20), ISNULL(@DateIn, '''OFF'''), 108) + ''', ' + CHAR(13) + CHAR(10) +
' [Exit ' + CONVERT(VARCHAR(12), @ForDate, 106) + '] = ''' + CONVERT(VARCHAR(20), ISNULL(@DateOut, '''OFF''', 108) + ''' WHERE UserID = ''' + @UserID + ''''
EXEC (@SQLstring)
DELETE #Times WHERE UserID = @UserID AND ForDate = @ForDate
END
Это дубликат для http://stackoverflow.com/questions/20882934/calculate-time-difference-for-attendance#20883190. – Jaques
@Jaques Нет, это не так. Мне нужно это на полный месяц не на один день. –
Вы можете создать новую таблицу, содержащую одну запись в день, и заполнить ее несколькими годами. Затем INNER ПРИСОЕДИНИТЕСЬ к этой новой таблице с CardEntry, и вы можете GROUP BY the day. Вам нужно будет поиграть, чтобы получить то, что вам нужно. – Brendan