使用sql查询在日期范围之间显示单列中多行值的总和

时间:2013-09-25 05:44:53

标签: sql sql-server

我有以下sql查询。

SELECT E.EMPID, TM.LOGIN, TM.LOGOUT, 
    SUM(DATEDIFF(MINUTE,TM.LOGIN,TM.LOGOUT)/60)+':'+
    SUM(DATEDIFF(MINUTE,TM.LOGIN,TM.LOGOUT)%60) AS WORKEDHOURS   
FROM EMPLOYEE_DETAILS E  
LEFT JOIN TIMING_DETAILS TM  
    ON(E.EMPID=TM.EMPID)  
WHERE TM.LOGIN BETWEEN '2013-09-02' AND DATEADD(DAY, 1, '2013-09-03')  
GROUP BY E.EMPID,TM.LOGIN,TM.LOGOUT  
ORDER BY E.EMPID

运行上面的查询后,我得到以下输出:

EMPID   LOGIN               LOGOUT          WORKEDHOURS  
1     2-9-2013 9:30      2-9-2013 1:00          3:30
1     2-9-2013 2:00      2-9-2013 6:00          4:00

2     2-9-2013 9:30      2-9-2013 2:00          4:30
2     2-9-2013 3:00      2-9-2013 6:00          3:00

1     3-9-2013 9:30      3-9-2013 6:00          8:30    

但是,我想显示结果如下,任何人请在这里帮忙,谢谢

EMPID   LOGIN               LOGOUT          WORKEDHOURS
1     2-9-2013 9:30      2-9-2013 1:00          7:30
1     2-9-2013 2:00      2-9-2013 6:00          

2     2-9-2013 9:30      2-9-2013 2:00          7:30
2     2-9-2013 3:00      2-9-2013 6:00          

1     3-9-2013 9:30      3-9-2013 6:00          8:30

4 个答案:

答案 0 :(得分:0)

编辑,找到了一个更简单的解决方案:

    SELECT T.EMPID, T.LOGIN, T.LOGOUT, X.WORKEDHOURS
FROM TIMING_DETAILS T
INNER JOIN
    (SELECT EMPID, DATEPART(YEAR, TM.LOGIN) YEAR, DATEPART(MONTH, TM.LOGIN) MONTH, DATEPART(DAY, TM.LOGIN) DAY,
        CAST(SUM(DATEDIFF(MINUTE,TM.LOGIN,TM.LOGOUT))/60 AS VARCHAR(MAX)) 
        + ':' 
        + CAST(SUM(DATEDIFF(MINUTE,TM.LOGIN,TM.LOGOUT))%60 AS VARCHAR(MAX)) AS WORKEDHOURS
    FROM TIMING_DETAILS TM
    WHERE TM.LOGIN BETWEEN '2013-09-02' AND DATEADD(DAY, 1, '2013-09-03') 
    GROUP BY EMPID, DATEPART(YEAR, TM.LOGIN), DATEPART(MONTH, TM.LOGIN), DATEPART(DAY, TM.LOGIN)) X
ON X.EMPID = T.EMPID 
    AND DATEPART(YEAR, T.LOGIN) = X.YEAR
    AND DATEPART(MONTH, T.LOGIN) = X.MONTH
    AND DATEPART(DAY, T.LOGIN) = X.DAY
ORDER BY X.EMPID, X.YEAR DESC, X.MONTH DESC, X.DAY DESC

答案 1 :(得分:0)

SELECT E.EMPID, TM.LOGIN, TM.LOGOUT,WORKHOURS_TABLE.WORKEDHOURS

FROM EMPLOYEE_DETAILS E, TIMING_DETAILS TM ,

(SELECT EMPID,
concat(
sum(hour(timeDIFF(TM.LOGOUT, TM.LOGIN )))
+ 
sum(minute(timeDIFF(TM.LOGOUT, TM.LOGIN ))) div 60 ,
":" , 
sum(minute(timeDIFF(TM.LOGOUT, TM.LOGIN ))) % 60
)

AS WORKEDHOURS 
FROM TIMING_DETAILS TM
GROUP BY EMPID) AS WORKHOURS_TABLE

WHERE E.EMPID =  WORKHOURS_TABLE.EMPID AND E.EMPID=TM.EMPID  
ORDER BY E.EMPID

输出可能是:

EMPID   LOGIN               LOGOUT          WORKEDHOURS
1     2-9-2013 9:30      2-9-2013 1:00          7:30
1     2-9-2013 2:00      2-9-2013 6:00          7:30

2     2-9-2013 9:30      2-9-2013 2:00          7:30
2     2-9-2013 3:00      2-9-2013 6:00          7:30

如果您想按日期分组,则必须为datetime分别保留一列,然后您可以按日期分组。

我在我的MySQL数据库中尝试了查询,它运行正常。你试试看。

答案 2 :(得分:0)

试试这个 -

SELECT  
      t.EMPID
    , t.LOGIN
    , t.LOGOUT
    , WORKEDHOURS = CASE WHEN rn = 1 THEN t.WORKEDHOURS END
FROM (
    SELECT 
          TM2.EMPID
        , TM2.LOGIN
        , TM2.LOGOUT
        , TM.WORKEDHOURS
        , rn = ROW_NUMBER() OVER (PARTITION BY TM2.EMPID ORDER BY TM2.EMPID) 
    FROM dbo.TIMING_DETAILS TM2
    JOIN (
        SELECT 
              EMPID
            , WORKEDHOURS = CAST(SUM(DATEDIFF(MINUTE, [login], LOGOUT)) / 60 AS VARCHAR(100)) + ':' + CAST(SUM(DATEDIFF(MINUTE, [login], LOGOUT)) % 60 AS VARCHAR(10)) 
        FROM dbo.TIMING_DETAILS
        WHERE [login] BETWEEN '20130902' AND '20130904'
        GROUP BY EMPID
    ) TM ON TM2.EMPID = TM.EMPID
    WHERE EXISTS( -- maybe this is unnecessary
         SELECT 1
         FROM dbo.EMPLOYEE_DETAILS E
         WHERE E.EMPID = TM2.EMPID 
    )
) t

答案 3 :(得分:0)

在我们的对话之后,以及与其他参与者一起审核您的对话时,我发现您的问题稍微受到限制。你真正想要的输出是这样的:

EMPID   DAY          WORKEDHOURS
    1   2-9-2013     7:30
    1   3-9-2013     8:30
    2   2-9-2013     7:30

案例1:范围内的单日

如果您只对一天感兴趣,那么您只需在结果中插入日期即可。请尝试以下方法:

SELECT E.EMPID,
       '2013-09-02' AS DAY,
       SUM(DATEDIFF(MINUTE,TM.LOGIN,TM.LOGOUT)/60)+':'+
       SUM(DATEDIFF(MINUTE,TM.LOGIN,TM.LOGOUT)%60) AS WORKEDHOURS   
FROM EMPLOYEE_DETAILS E  
     LEFT JOIN TIMING_DETAILS TM  
     ON (E.EMPID=TM.EMPID)  
WHERE TM.LOGIN BETWEEN '2013-09-02' AND DATEADD(DAY, 1, '2013-09-03')
GROUP BY E.EMPID
ORDER BY E.EMPID

您还可以重写查询以使用命名参数作为相关日期。这是一个示例,但要使用它,您必须将值绑定到参数TheDay

SELECT E.EMPID,
       @TheDay AS DAY,
       SUM(DATEDIFF(MINUTE,TM.LOGIN,TM.LOGOUT)/60)+':'+
       SUM(DATEDIFF(MINUTE,TM.LOGIN,TM.LOGOUT)%60) AS WORKEDHOURS   
FROM EMPLOYEE_DETAILS E  
     LEFT JOIN TIMING_DETAILS TM  
     ON (E.EMPID=TM.EMPID)  
WHERE TM.LOGIN BETWEEN @TheDay AND DATEADD(DAY, 1, @TheDay)
GROUP BY E.EMPID
ORDER BY E.EMPID

案例2:范围内的多天

如果每个EMPID需要多行,但每天只需要一行,那么事情会更复杂。我认为有可能在几个(也许是所有)DBMS中,但可能需要使用非便携式功能。我们需要做的是GROUP BY LOGIN日期时间值的日期部分。

如果您使用的是SQL Server 2008(或更新版本),则可以尝试以下操作:

SELECT E.EMPID,
       CAST(TM.LOGIN AS DATE) AS DAY,
       SUM(DATEDIFF(MINUTE,TM.LOGIN,TM.LOGOUT)/60)+':'+
       SUM(DATEDIFF(MINUTE,TM.LOGIN,TM.LOGOUT)%60) AS WORKEDHOURS   
FROM EMPLOYEE_DETAILS E  
     LEFT JOIN TIMING_DETAILS TM  
     ON (E.EMPID=TM.EMPID)  
WHERE TM.LOGIN BETWEEN '2013-09-02' AND DATEADD(DAY, 1, '2013-09-03')
GROUP BY E.EMPID, CAST(TM.LOGIN AS DATE)
ORDER BY E.EMPID

请注意,我无法测试此查询。例如,您可能必须GROUP BY DAY而不是重复表达。

案例2B:范围内的多天,首次登录和最后一次登录

您是否希望每个EMPID每天一行,但第一次登录时间和上次注销时间?您可以尝试以下方法:

SELECT E.EMPID,
       MIN(TM.LOGIN) AS FIRSTLOGIN,
       MAX(TM.LOGOUT) AS LASTLOGOUT,
       SUM(DATEDIFF(MINUTE,TM.LOGIN,TM.LOGOUT)/60)+':'+
       SUM(DATEDIFF(MINUTE,TM.LOGIN,TM.LOGOUT)%60) AS WORKEDHOURS   
FROM EMPLOYEE_DETAILS E  
     LEFT JOIN TIMING_DETAILS TM  
     ON (E.EMPID=TM.EMPID)  
WHERE TM.LOGIN BETWEEN '2013-09-02' AND DATEADD(DAY, 1, '2013-09-03')
GROUP BY E.EMPID, CAST(TM.LOGIN AS DATE)
ORDER BY E.EMPID

同样,我还没有能力测试这个查询。

TESTED CASE:对Visual Studio 2010中本地SQL Server Express数据库的查询

我今天无法在Sql Server上进行测试,但这是我在本地Sql Server Express数据库上在Visual Studio 2010下测试的查询版本。

SELECT
    E.EMPID, E.NAME,
    MIN(TM.LOGIN) AS FirstLogIn,
    MAX(TM.LOGOUT) AS LastLogOut,
    CAST(SUM(DATEDIFF(MINUTE, TM.LOGIN, TM.LOGOUT) / 60) AS NVARCHAR)+':'+CAST(SUM(DATEDIFF(MINUTE, TM.LOGIN, TM.LOGOUT) % 60) AS NVARCHAR) AS WorkedHours
FROM
    EMPLOYEE_DETAILS AS E LEFT OUTER JOIN TIMING_DETAILS AS TM ON E.EMPID = TM.EMPID
WHERE
    TM.LOGIN BETWEEN '2013-09-21' AND DATEADD(DAY, 1, '2013-09-22')
GROUP BY
    E.EMPID, E.NAME,
    DATEADD(DAY, DATEDIFF(DAY, 0, TM.LOGIN), 0)
ORDER BY
    E.EMPID, FirstLogin

测试数据EMPLOYEE_DETAILS:

EMPID    NAME
1        Joe
2        Jane
3        Martha

测试数据TIMING_DETAILS:

EMPID    LOGIN                    LOGOUT
1        '2013-09-21 09:00:00'    '2013-09-21 10:30:00'
1        '2013-09-21 14:00:00'    '2013-09-21 16:00:00'
1        '2013-09-22 08:30:00'    '2013-09-22 11:00:00'
2        '2013-09-21 10:45:00'    '2013-09-21 13:30:00'

结果:

EMPID    NAME   FirstLogIn               LastLogOut               WorkedHours
1        Joe    '2013-09-21 09:00:00'    '2013-09-21 16:00:00'    3:30
1        Joe    '2013-09-22 08:30:00'    '2013-09-22 11:00:00'    2:30
2        Jane   '2013-09-21 10:45:00'    '2013-09-21 13:30:00'    2:45

这对我来说似乎是对的。我的SQL Server Express查询的唯一区别是它不提供DATE类型,因此我不得不修改CAST。哦,我还必须明确地向NVARCHAR投入WorkedHours。

请根据您的环境进行相应调整。

希望这有帮助。