2014-01-03 2 views
0

У меня есть две таблицы, одна из которых - Tab_Users, содержащая данные пользователя, а другая - Tab_CardEntry, содержащая их записи в карточке. Мне нужно ежедневно получать минимальное и максимальное время входа в карточку для каждого пользователя.Сотрудник Ежемесячный Посещаемость с использованием SQL Server

Вот SQL-запрос я использовал

SELECT 
    A.Name, 
    ISNULL(CONVERT(VARCHAR, MIN(B.DATED), 108), 'OFF') LOGEDIN, 
    ISNULL(CONVERT(VARCHAR, MAX(B.DATED), 108), 'OFF') LOGEDOUT 
FROM TAB_USERS A 
LEFT OUTER JOIN (
    SELECT 
     USERNAME, 
     DATED 
    FROM TAB_CARDENTRY 
    WHERE CONVERT(VARCHAR, DATED, 106) = CONVERT(VARCHAR, '02 Jan 2014', 106) 
) B ON A.USERNAME = B.USERNAME 
GROUP BY A.Name 
ORDER BY 1 

Мне нужен этот тип вывода

enter image description here

+0

Это дубликат для http://stackoverflow.com/questions/20882934/calculate-time-difference-for-attendance#20883190. – Jaques

+0

@Jaques Нет, это не так. Мне нужно это на полный месяц не на один день. –

+0

Вы можете создать новую таблицу, содержащую одну запись в день, и заполнить ее несколькими годами. Затем INNER ПРИСОЕДИНИТЕСЬ к этой новой таблице с CardEntry, и вы можете GROUP BY the day. Вам нужно будет поиграть, чтобы получить то, что вам нужно. – Brendan

ответ

0

Вот ХП, которые вы можете попробовать

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 
+0

Thanks.but get error usp_GetTimes '1-dec-2013', '31-dec-2013' Msg 2715, Level 16, State 7, Line 1 Столбец, параметр или переменная # 2: Не удается найти время типа данных. –

+0

Я думал, что вы используете SQL 2012. Сделайте это datetime, и он должен работать. – Jaques

Смежные вопросы