当前位置: 首页 > 面试题库 >

从门禁表中选择先进先出时间

柯昆
2023-03-14
问题内容

这是我的门禁桌[dbo]。[tblAccess]

+------------+--------------+----------+-----------------+------------+
| EmployeeId | EmployeeName | Location |   AccessTime    | ReaderType |
+------------+--------------+----------+-----------------+------------+
| _1346      | A            | L1       | 7/11/2014 10:00 | IN         |
| _1347      | B            | L2       | 7/10/2014 10:58 | IN         |
| _1346      | A            | L3       | 7/11/2014 23:39 | OUT        |
| _1347      | B            | L4       | 7/10/2014 23:58 | OUT        |
| _1364      | C            | L5       | 7/11/2014 10:00 | IN         |
| _1367      | D            | L6       | 7/10/2014 10:58 | IN         |
| _1367      | D            | L7       | 7/10/2014 22:42 | OUT        |
| _1364      | C            | L8       | 7/11/2014 23:58 | OUT        |
| _1422      | E            | L9       | 7/11/2014 23:58 | IN         |
| _1422      | E            | L10      | 7/11/2014 23:10 | IN         |
| _1111      | F            | L20      | 7/10/2014 23:10 | OUT        |
+------------+--------------+----------+-----------------+------------+

情况

  • 假设员工将在同一天进出。
  • 员工当天将有多个进出,因此需要先进后出。
  • 需要每天获取详细信息,两个日期之间,按EmployeeId分组
  • 员工的(InTime,InLocation)或(OUTTime,OutLocation)可以为null
  • 如果(InTime)为null,则FirstInLocation和duration将为null,并且与OutTime相同( 结果1中显示 )。[如果很难,则不要显示IN时间或OUT时间为零的那一天的详细信息( 在结果2中显示 )]
  • 持续时间=(FirstInTime-LastOutTime)

需要的结果

我想选择EmployeeId,EmployeeName,Date,FirstInTime,FirstInLocation,LastOutTime,LastOutLocation,持续时间。

结果1

+-------+---------+-----------+-------+--------+--------+---------+---------+
| EmpID | EmpName |   Date    | InLoc | InTime | OutLoc | OutTime | Dur(Hr) |
+-------+---------+-----------+-------+--------+--------+---------+---------+
| _1346 | A       | 7/11/2014 | L1    | 10:00  | L3     | 23:39   | 13:39   |
| _1347 | B       | 7/10/2014 | L2    | 10:58  | L4     | 23:58   | 13:02   |
| _1364 | C       | 7/11/2014 | L5    | 10:00  | L8     | 23:58   | 13:58   |
| _1367 | D       | 7/10/2014 | L6    | 10:58  | L7     | 22:42   | 11:44   |
| _1422 | E       | 7/10/2014 | L10   | 23:10  |        |         |         |
| _1111 | F       | 7/10/2014 |       |        | L20    | 23:10   |         |
+-------+---------+-----------+-------+--------+--------+---------+---------+

或者

只需跳过空的IN或OUT行。像这样的东西。

结果2

+-------+---------+-----------+-------+--------+--------+---------+---------+
| EmpID | EmpName |   Date    | InLoc | InTime | OutLoc | OutTime | Dur(Hr) |
+-------+---------+-----------+-------+--------+--------+---------+---------+
| _1346 | A       | 7/11/2014 | L1    | 10:00  | L3     | 23:39   | 13:39   |
| _1347 | B       | 7/10/2014 | L2    | 10:58  | L4     | 23:58   | 13:02   |
| _1364 | C       | 7/11/2014 | L5    | 10:00  | L8     | 23:58   | 13:58   |
| _1367 | D       | 7/10/2014 | L6    | 10:58  | L7     | 22:42   | 11:44   |
+-------+---------+-----------+-------+--------+--------+---------+---------+

到目前为止,我已经通过以下链接进行了一些查询。但是它的解决方案不完整,而且我是CTE的新手,因此我无法编辑链接中给出的任何查询。

  • 如何从SQL Server获取首次登录和最后退出时间?
  • SQL查询出入勤
  • http://database.ittoolbox.com/groups/technical-functional/sql-l/query-to-pair-user-biometric-attendance-record-in-first-in-last-out-format-5132155

我有这个查询。

    ;with cte as
(select *, rank() over(partition by EmployeeId order by [AccessTime]) rn
 from tblAccess)

select src.EmployeeId, src.EmployeeName, convert(date, src.[AccessTime]) as [AccessTime],
concat(datepart(hour,src.[AccessTime]),':',datepart(minute,src.[AccessTime])) as [TimeIn],
concat(datepart(hour,tgt.[AccessTime]),':',datepart(minute,tgt.[AccessTime])) as [TimeOut],
concat(datediff(minute,src.[AccessTime],tgt.[AccessTime])/60,':',datediff(minute,src.[AccessTime],tgt. [AccessTime])%60) as [Hours]
from cte src
inner join cte tgt on src.EmployeeId = tgt.EmployeeId and src.rn + 1 = tgt.rn and src.rn % 2 = 1

它可以返回结果,但是可以满足所有条件。我不熟悉如何编辑CTE。有什么办法吗?


问题答案:

试试这个:

样本数据

CREATE TABLE tblAccess(
    EmployeeID      VARCHAR(20),
    EmployeeName    VARCHAR(20),
    Location        VARCHAR(20),
    AccessTime      DATETIME,
    ReaderType      VARCHAR(3)
)
INSERT INTO tblAccess VALUES
('_1346', 'A', 'L1', '7/11/2014 10:00', 'IN'),
('_1347', 'B', 'L2', '7/10/2014 10:58', 'IN'),
('_1346', 'A', 'L3', '7/11/2014 23:39', 'OUT'),
('_1347', 'B', 'L4', '7/10/2014 23:58', 'OUT'),
('_1364', 'C', 'L5', '7/11/2014 10:00', 'IN'),
('_1367', 'D', 'L6', '7/10/2014 10:58', 'IN'),
('_1367', 'D', 'L7', '7/10/2014 22:42', 'OUT'),
('_1364', 'C', 'L8', '7/11/2014 23:58', 'OUT'),
('_1422', 'E', 'L9', '7/11/2014 23:58', 'IN'),
('_1422', 'E', 'L10', '7/11/2014 23:10', 'IN'),
('_1111', 'F', 'L20', '7/10/2014 23:10', 'OUT');

解决方案

;WITH CTE AS(
    SELECT
        EmployeeID,
        EmployeeName,
        AccessDate = CAST(AccessTime AS DATE),
        AccessTime = CAST(AccessTime AS TIME),
        Location,
        ReaderType,
        In_RN = ROW_NUMBER() OVER(PARTITION BY EmployeeId, CAST(AccessTime AS DATE), ReaderType ORDER BY CAST(AccessTime AS TIME) ASC),
        Out_RN = ROW_NUMBER() OVER(PARTITION BY EmployeeId, CAST(AccessTime AS DATE), ReaderType ORDER BY CAST(AccessTime AS TIME) DESC)
    FROM tblAccess
)
SELECT
    EmployeeID,
    EmployeeName,
    [Date] = CONVERT(VARCHAR(10), AccessDate, 101),
    InLoc = ISNULL(MAX(CASE WHEN ReaderType = 'IN' AND In_RN = 1 THEN Location END), ''),
    InTime= ISNULL(SUBSTRING(CONVERT(VARCHAR(20), MAX(CASE WHEN ReaderType = 'IN' AND In_RN = 1 THEN AccessTime END)), 1, 5), ''),
    OutLoc = ISNULL(MAX(CASE WHEN ReaderType = 'OUT' AND OUT_RN = 1 THEN Location END), ''),
    OutTime = ISNULL(SUBSTRING(CONVERT(VARCHAR(20), MAX(CASE WHEN ReaderType = 'OUT' AND OUT_RN = 1 THEN AccessTime END)), 1, 5), ''),
    Duration =  ISNULL(RIGHT('00' +             
                CONVERT(VARCHAR(2), DATEDIFF(MINUTE, 
                    MAX(CASE WHEN ReaderType = 'IN' AND In_RN = 1 THEN AccessTime END), 
                    MAX(CASE WHEN ReaderType = 'OUT' AND OUT_RN = 1 THEN AccessTime END)
                )/60), 2) + ':' +
                RIGHT('00' +CONVERT(VARCHAR(2), DATEDIFF(MINUTE, 
                    MAX(CASE WHEN ReaderType = 'IN' AND In_RN = 1 THEN AccessTime END), 
                    MAX(CASE WHEN ReaderType = 'OUT' AND OUT_RN = 1 THEN AccessTime END)
                )%60), 2)
            ,'')
FROM CTE
GROUP BY EmployeeID, EmployeeName, AccessDate
ORDER BY EmployeeName, AccessDate

结果

EmployeeID           EmployeeName Date       InLoc    InTime OutLoc  OutTime Duration
-------------------- ------------ ---------- -------- ------ ------- ------- --------
_1346                A            07/11/2014 L1       10:00  L3      23:39   13:39
_1347                B            07/10/2014 L2       10:58  L4      23:58   13:00
_1364                C            07/11/2014 L5       10:00  L8      23:58   13:58
_1367                D            07/10/2014 L6       10:58  L7      22:42   11:44
_1422                E            07/11/2014 L10      23:10          
_1111                F            07/10/2014                 L20     23:10


 类似资料:
  • 问题内容: 我知道这是在黑暗中拍摄的,但是有没有办法仅使用CSS,CSS2,没有jquery,没有javascript来选择和设置元素祖先的样式?我已经遍历了选择器,但是发布了它,以防万一我错过了一些东西或者有一个聪明的解决方法。 例如,假设我有一个嵌套在div中的类名称为“ test”的表。是否有某种: 问题答案: CSS2或CSS3中没有父选择器之类的东西。实际上,可能永远不会存在,因为一旦开

  • 介绍 FIFO(first in first out) 先进先出策略。元素不停的加入缓存直到缓存满为止,当缓存满时,清理过期缓存对象,清理后依旧满则删除先入的缓存(链表首部对象)。 优点:简单快速 缺点:不灵活,不能保证最常用的对象总是被保留 使用 Cache<String,String> fifoCache = CacheUtil.newFIFOCache(3); //加入元素,每个元素可以设

  • 问题内容: 对此不熟悉,尝试按照著名的Flask教程使用Flask-bootstrap,Flask-wtforms,Jinja等构建一个应用程序 我有一个带有2个选择字段和一个按钮的表单。 我只希望第一个字段预先填充,而另一个字段根据前一个字段的选定值填充(在客户端?)。 在模板中,我尝试类似 可以正常工作(只要我返回元组列表以使用正确的javascript和路由填充下一个字段),但我想要以下内容

  • 我现在有一张表,示例如下, 其中总数列是每个产品要出库的数量, ShipmentID是出库的批次,每个产品可能有很多个批次(虽然示例表只给了一个) 每个产品都对应了很多订单,预计到货时间列是订单号对应的到货时间, 待到货量即订单的数量, 现在需要把每个订单中的待到货量按先进先出即预计到货时间在前的先出,分配给不同批次的出库量。 得到的结果如下图所示。 我根据网上搜到的提示,写了半天,写出几行代码,

  • 问题内容: 假设我有一些SKU的购买和销售数据: 假设按购买顺序出售,我如何通过SQL查找销售利润率?例如,sku 123的保证金是 其中有2件以17.50购买,还有1件以15.00购买尚未售出。 问题答案: 好问题。我采用的方法是计算总销售额。然后计算累计购买量,并将其与特殊逻辑结合起来以得出正确的结合算术: 注意:我尚未测试此查询,因此它可能存在语法错误。

  • 王军霞跑得快,能得奥运会冠军,人家跑步是有技术的。动不动就一万几千米地跑你就要学会前紧后松,要是一上来就百米冲刺般跑出去,前面倒是能领先好一阵,可好景不长,最后不要说拿第一名,连名次都没有就可惜了,毕竟你还为了这事还花去了好大体力。 但牛人也例外,记得绝影还是年大学的时候,有一次体育考一千米跑,几个人跑下来累得像猪一样,却发现旁边有个不认识的猛男一直保持着冲刺的速度。一干女生无不羡慕地说:“你看人