0

我真的可以使用一些帮助来确定以下场景的查询。

tblStaff

| ESID | EID | FName | LName  |
+------+-----+-------+--------+
| 1    | 10  | Joe   | Smith  |
| 2    | 10  | Dan   | Jones  |
| 3    | 10  | Rick  | Brown  |
| 4    | 10  | Pete  | Miller |
| 5    | 10  | Ken   | White  |

tblStaffTime

| TCID | EID | ESID | DTIn                    | DTOut                   |
+------+-----+------+-------------------------+-------------------------+
| 1    | 10  | 1    | 2013-09-22 08:00:00.000 | 2013-09-22 17:00:00.000 |
| 2    | 10  | 1    | 2013-09-23 08:00:00.000 | NULL                    |
| 3    | 10  | 2    | 2013-09-23 08:00:00.000 | 2013-09-23 17:00:00.000 |
| 4    | 10  | 3    | 2013-09-22 08:00:00.000 | 2013-09-22 17:00:00.000 |
| 5    | 10  | 3    | 2013-09-23 08:00:00.000 | NULL                    |

我的目标是:列出所有 EID 等于 10 的人,其中最近的 DTOut 不为空,或者他们在 tblStaffTime 中根本没有此 EID 的记录。换句话说,为所有 EID 等于 10 的员工准备好打卡人员的列表。

到目前为止我的 SQL:

SELECT tblStaff.ESID AS ID,tblStaff.SFirst + CHAR(32) + tblStaff.SLast AS StaffName
FROM tblStaff
LEFT JOIN tblStaffTime ON tblStaff.ESID = tblStaffTime.ESID
WHERE tblStaff.ESID = (SELECT ESID FROM tblStaffTime WHERE EID = '10' AND ESID = tblStaffTime.ESID AND DTIn IS NOT NULL AND DTOut IS NOT NULL)
UNION ALL
SELECT tblStaff.ESID AS ID,tblStaff.SFirst + CHAR(32) + tblStaff.SLast AS StaffName
FROM tblStaff
LEFT JOIN tblStaffTime ON tblStaff.ESID = tblStaffTime.ESID
WHERE NOT EXISTS (SELECT 1 FROM tblStaffTime WHERE tblStaffTime.ESID = tblStaff.ESID) AND tblStaff.EID = '10'
ORDER BY tblStaff.SFirst + CHAR(32) + tblStaff.SLast

期望的输出:

| ESID | StaffName   |
+------+-------------+
| 2    | Dan Jones   |
| 5    | Ken White   |
| 4    | Pete Miller |

South of my Union 解决了我让尚未为此 EID 打卡的员工的问题。我的主要问题是我工会的北部。我需要获取最新的 DTIn 并查看该记录的 DTOut 是否为空,以确定它们是否应该被列为准备打卡。我确信这个 SQL 都可以写得更干净。我现在把它留给专家。

4

1 回答 1

1

如果您使用的是 SQL Server 2005 或更高版本,则可以使用窗口函数来帮助解决此问题

左外连接有助于包括没有记录的人,DTIn 的顺序让我们在有记录时选择最新的时间记录

With x as (
    Select
        s.ESID,
        s.EID,
        s.FName,
        s.LName,
        t.DTIn,
        t.DTOut,
        row_number() over (partition by s.ESID, s.EID order by DTIn Desc) rn
    From
        tblStaff s
            Left Outer Join
        tblStaffTime t
            On s.ESID = t.ESID and s.EID = t.EID
)
Select
    x.ESID,
    x.EID,
    x.FName,
    x.LName
From
    x
Where
    x.EID = 10 And
    x.rn = 1 And (
      x.DTIn Is Null Or -- no time records
      x.DTOut IS Not Null -- latest time record has not null clock out
    )

Example Fiddle

于 2013-09-26T20:49:09.777 回答