使用 LEFT JOIN 和 ON 语句仅选择最接近的值
Selecting only the closest value using LEFT JOIN and ON statement
我对如何使用 LEFTJOIN 执行此操作有疑问。 LEFT JOIN
和 ON
有没有办法在查询中专门选择 最接近的值 LEFT JOIN
?
例如,我有来自下面这样的查询的值,它是根据检查日期排序的,我根据 2019-12-25 对值进行了排序.我只想 select 最接近 2019-12-25 14:50:00.000 的值,因此,从技术上讲,唯一应该使用的值是 2019-12-25 14:51:57.000 因为它最近,我们如何使用 LEFT JOIN
?
+-------------+-----------+-------------------------+------------+
| badgenumber | checktype | recordout | checkdate |
+-------------+-----------+-------------------------+------------+
| 1233 | O | 2019-12-25 14:00:02.000 | 2019-12-25 |
+-------------+-----------+-------------------------+------------+
| 1233 | O | 2019-12-25 14:39:57.000 | 2019-12-25 |
+-------------+-----------+-------------------------+------------+
| 1233 | O | 2019-12-25 14:51:57.000 | 2019-12-25 |
+-------------+-----------+-------------------------+------------+
| 1233 | O | 2019-12-25 22:41:57.000 | 2019-12-25 |
+-------------+-----------+-------------------------+------------+
| 1233 | O | 2019-12-25 22:52:57.000 | 2019-12-25 |
+-------------+-----------+-------------------------+------------+
这是我正在处理的查询,employeeidno, fullname, departmentname
是隐藏的。
使用的值如下。
- t0.noofhoursduty = 8
- t0.mergetimeoutorig = 2019-12-25 14:50:00.000
这是包含 LEFT JOIN
的查询。
LEFT JOIN
(SELECT
MAX(userinfo.badgenumber) AS badgenumber,
MAX(RTRIM(checkinout.checktype)) AS 'checktype',
MAX(checkinout.checktime) as 'recordout',
MAX(CONVERT(date,checkinout.checktime)) as checkdate,
MAX(RTRIM(employeemasterfile.employeeidno)) AS 'employeeidno',
MAX(RTRIM(employeemasterfile.lastname))+', '+
MAX(RTRIM(employeemasterfile.firstname))+' '+ MAX(LEFT(employeemasterfile.middlename,1))+'.' AS 'fullname',
MAX(RTRIM(departmentmasterfile.departmentname)) AS 'departmentname'
FROM ((checkinout INNER JOIN userinfo
ON checkinout.userid = userinfo.userid)
INNER JOIN employeemasterfile
ON userinfo.badgenumber = employeemasterfile.fingerscanno)
INNER JOIN departmentmasterfile
ON LEFT(employeemasterfile.employeeidno, 4) = LEFT(departmentmasterfile.departmentcode, 4)
WHERE
CONVERT(date,checkinout.checktime) BETWEEN '2019-12-21' AND DATEADD(DAY, 1,'2020-01-05')
AND CHECKINOUT.CHECKTYPE = 'O' COLLATE SQL_Latin1_General_CP1_CS_AS
GROUP BY
userinfo.badgenumber, LEFT(checkinout.checktime,14)) AS t2
ON
t2.recordout BETWEEN DATEADD(HOUR,-(t0.noofhoursduty/2),t0.mergetimeoutorig) AND DATEADD(HOUR, 1,t0.mergetimeoutorig)
AND t2.badgenumber = t0.fingerscanno
AND t0.schedulename !='REST'
这将是上面查询的输出。相同日期的结果是可以的,因为在某些情况下,一个人在不同的时间戳中一天登录 4 次。或者一个人一天有 2 个或更多的日程安排。
+-------------+-----------+-------------------------+------------+--------------+----------+----------------+
| badgenumber | checktype | recordout | checkdate | employeeidno | fullname | departmentname |
+-------------+-----------+-------------------------+------------+--------------+----------+----------------+
| 1233 | O | 2019-12-21 23:43:36.000 | 2019-12-21 | ------------ | -------- | -------------- |
+-------------+-----------+-------------------------+------------+--------------+----------+----------------+
| 1233 | O | 2019-12-22 22:36:50.000 | 2019-12-22 | ------------ | -------- | -------------- |
+-------------+-----------+-------------------------+------------+--------------+----------+----------------+
| 1233 | O | 2019-12-23 18:03:16.000 | 2019-12-23 | ------------ | -------- | -------------- |
+-------------+-----------+-------------------------+------------+--------------+----------+----------------+
| 1233 | O | 2019-12-24 22:06:58.000 | 2019-12-24 | ------------ | -------- | -------------- |
+-------------+-----------+-------------------------+------------+--------------+----------+----------------+
| 1233 | O | 2019-12-25 14:00:02.000 | 2019-12-25 | ------------ | -------- | -------------- |
+-------------+-----------+-------------------------+------------+--------------+----------+----------------+
| 1233 | O | 2019-12-25 14:39:57.000 | 2019-12-25 | ------------ | -------- | -------------- |
+-------------+-----------+-------------------------+------------+--------------+----------+----------------+
| 1233 | O | 2019-12-25 14:51:57.000 | 2019-12-25 | ------------ | -------- | -------------- |
+-------------+-----------+-------------------------+------------+--------------+----------+----------------+
| 1233 | O | 2019-12-25 22:41:57.000 | 2019-12-25 | ------------ | -------- | -------------- |
+-------------+-----------+-------------------------+------------+--------------+----------+----------------+
| 1233 | O | 2019-12-25 22:52:57.000 | 2019-12-25 | ------------ | -------- | -------------- |
+-------------+-----------+-------------------------+------------+--------------+----------+----------------+
| 1233 | O | 2019-12-26 14:00:02.000 | 2019-12-26 | ------------ | -------- | -------------- |
+-------------+-----------+-------------------------+------------+--------------+----------+----------------+
| 1233 | O | 2019-12-28 22:00:01.000 | 2019-12-28 | ------------ | -------- | -------------- |
+-------------+-----------+-------------------------+------------+--------------+----------+----------------+
| 1233 | O | 2019-12-28 23:31:11.000 | 2019-12-28 | ------------ | -------- | -------------- |
+-------------+-----------+-------------------------+------------+--------------+----------+----------------+
| 1233 | O | 2019-12-29 15:08:10.000 | 2019-12-29 | ------------ | -------- | -------------- |
+-------------+-----------+-------------------------+------------+--------------+----------+----------------+
| 1233 | O | 2019-12-30 16:03:20.000 | 2019-12-30 | ------------ | -------- | -------------- |
+-------------+-----------+-------------------------+------------+--------------+----------+----------------+
| 1233 | O | 2020-01-02 06:52:18.000 | 2020-01-02 | ------------ | -------- | -------------- |
+-------------+-----------+-------------------------+------------+--------------+----------+----------------+
| 1233 | O | 2020-01-03 08:00:57.000 | 2020-01-03 | ------------ | -------- | -------------- |
+-------------+-----------+-------------------------+------------+--------------+----------+----------------+
| 1233 | O | 2020-01-04 06:40:11.000 | 2020-01-04 | ------------ | -------- | -------------- |
+-------------+-----------+-------------------------+------------+--------------+----------+----------------+
我目前得到的东西现在似乎可以工作,但是当时间戳有很大差异时,数据就会重复,例如,如果人时间戳 'O' (checktype) 在 左右12AM - 9AM 并在 10AM - 7PM 左右再次按下,记录将显示同一日期内的 2 个数据,没关系,我的主要问题是我们如何 select 仅在 LEFT JOIN
?
中与其最接近的值
总而言之,如果我要使用 2019-12-25,是否有办法让 LEFT JOIN
仅根据记录输出 select 最接近的值14:50:00.000作为LEFT JOIN的基础,那么只有2019-12-25 14:51:57.000应该是select为 LEFT JOIN 编辑。我尝试使用 BETWEEN
和 DATEADD(-+HOUR)
,但它仍然 selecting 同一记录输出中的所有数据。有没有办法做到这一点?或者仅使用 LEFT JOIN
?
是合理的
有没有办法修改这行代码来达到我的目标?
ON
t2.recordout BETWEEN DATEADD(HOUR,-(t0.noofhoursduty/2),t0.mergetimeoutorig) AND DATEADD(HOUR, 1,t0.mergetimeoutorig)
AND t2.badgenumber = t0.fingerscanno
AND t0.schedulename !='REST'
希望得到积极的回应,关于如何使用 LEFT JOIN 执行此操作一直困扰我很长时间。
使用 OUTER APPLY 而不是 LEFT JOIN 并且 select 仅第一个匹配行使用正确的顺序,类似这样:
...
OUTER APPLY (
select top(1) *
from (
SELECT
MAX(userinfo.badgenumber) AS badgenumber,
-- you current t2 subquery
) AS t2
where
t2.recordout BETWEEN DATEADD(HOUR,-(t0.noofhoursduty/2),t0.mergetimeoutorig) AND DATEADD(HOUR, 1,t0.mergetimeoutorig)
AND t2.badgenumber = t0.fingerscanno
AND t0.schedulename !='REST'
order by abs(datediff(minute, t0.mergetimeoutorig, t2.recordout )) desc
) t2
这不是一个有效的查询,因为我没有看到示例数据和 table 结构,但希望它有助于找到正确的方向。
我对如何使用 LEFTJOIN 执行此操作有疑问。 LEFT JOIN
和 ON
有没有办法在查询中专门选择 最接近的值 LEFT JOIN
?
例如,我有来自下面这样的查询的值,它是根据检查日期排序的,我根据 2019-12-25 对值进行了排序.我只想 select 最接近 2019-12-25 14:50:00.000 的值,因此,从技术上讲,唯一应该使用的值是 2019-12-25 14:51:57.000 因为它最近,我们如何使用 LEFT JOIN
?
+-------------+-----------+-------------------------+------------+
| badgenumber | checktype | recordout | checkdate |
+-------------+-----------+-------------------------+------------+
| 1233 | O | 2019-12-25 14:00:02.000 | 2019-12-25 |
+-------------+-----------+-------------------------+------------+
| 1233 | O | 2019-12-25 14:39:57.000 | 2019-12-25 |
+-------------+-----------+-------------------------+------------+
| 1233 | O | 2019-12-25 14:51:57.000 | 2019-12-25 |
+-------------+-----------+-------------------------+------------+
| 1233 | O | 2019-12-25 22:41:57.000 | 2019-12-25 |
+-------------+-----------+-------------------------+------------+
| 1233 | O | 2019-12-25 22:52:57.000 | 2019-12-25 |
+-------------+-----------+-------------------------+------------+
这是我正在处理的查询,employeeidno, fullname, departmentname
是隐藏的。
使用的值如下。
- t0.noofhoursduty = 8
- t0.mergetimeoutorig = 2019-12-25 14:50:00.000
这是包含 LEFT JOIN
的查询。
LEFT JOIN
(SELECT
MAX(userinfo.badgenumber) AS badgenumber,
MAX(RTRIM(checkinout.checktype)) AS 'checktype',
MAX(checkinout.checktime) as 'recordout',
MAX(CONVERT(date,checkinout.checktime)) as checkdate,
MAX(RTRIM(employeemasterfile.employeeidno)) AS 'employeeidno',
MAX(RTRIM(employeemasterfile.lastname))+', '+
MAX(RTRIM(employeemasterfile.firstname))+' '+ MAX(LEFT(employeemasterfile.middlename,1))+'.' AS 'fullname',
MAX(RTRIM(departmentmasterfile.departmentname)) AS 'departmentname'
FROM ((checkinout INNER JOIN userinfo
ON checkinout.userid = userinfo.userid)
INNER JOIN employeemasterfile
ON userinfo.badgenumber = employeemasterfile.fingerscanno)
INNER JOIN departmentmasterfile
ON LEFT(employeemasterfile.employeeidno, 4) = LEFT(departmentmasterfile.departmentcode, 4)
WHERE
CONVERT(date,checkinout.checktime) BETWEEN '2019-12-21' AND DATEADD(DAY, 1,'2020-01-05')
AND CHECKINOUT.CHECKTYPE = 'O' COLLATE SQL_Latin1_General_CP1_CS_AS
GROUP BY
userinfo.badgenumber, LEFT(checkinout.checktime,14)) AS t2
ON
t2.recordout BETWEEN DATEADD(HOUR,-(t0.noofhoursduty/2),t0.mergetimeoutorig) AND DATEADD(HOUR, 1,t0.mergetimeoutorig)
AND t2.badgenumber = t0.fingerscanno
AND t0.schedulename !='REST'
这将是上面查询的输出。相同日期的结果是可以的,因为在某些情况下,一个人在不同的时间戳中一天登录 4 次。或者一个人一天有 2 个或更多的日程安排。
+-------------+-----------+-------------------------+------------+--------------+----------+----------------+
| badgenumber | checktype | recordout | checkdate | employeeidno | fullname | departmentname |
+-------------+-----------+-------------------------+------------+--------------+----------+----------------+
| 1233 | O | 2019-12-21 23:43:36.000 | 2019-12-21 | ------------ | -------- | -------------- |
+-------------+-----------+-------------------------+------------+--------------+----------+----------------+
| 1233 | O | 2019-12-22 22:36:50.000 | 2019-12-22 | ------------ | -------- | -------------- |
+-------------+-----------+-------------------------+------------+--------------+----------+----------------+
| 1233 | O | 2019-12-23 18:03:16.000 | 2019-12-23 | ------------ | -------- | -------------- |
+-------------+-----------+-------------------------+------------+--------------+----------+----------------+
| 1233 | O | 2019-12-24 22:06:58.000 | 2019-12-24 | ------------ | -------- | -------------- |
+-------------+-----------+-------------------------+------------+--------------+----------+----------------+
| 1233 | O | 2019-12-25 14:00:02.000 | 2019-12-25 | ------------ | -------- | -------------- |
+-------------+-----------+-------------------------+------------+--------------+----------+----------------+
| 1233 | O | 2019-12-25 14:39:57.000 | 2019-12-25 | ------------ | -------- | -------------- |
+-------------+-----------+-------------------------+------------+--------------+----------+----------------+
| 1233 | O | 2019-12-25 14:51:57.000 | 2019-12-25 | ------------ | -------- | -------------- |
+-------------+-----------+-------------------------+------------+--------------+----------+----------------+
| 1233 | O | 2019-12-25 22:41:57.000 | 2019-12-25 | ------------ | -------- | -------------- |
+-------------+-----------+-------------------------+------------+--------------+----------+----------------+
| 1233 | O | 2019-12-25 22:52:57.000 | 2019-12-25 | ------------ | -------- | -------------- |
+-------------+-----------+-------------------------+------------+--------------+----------+----------------+
| 1233 | O | 2019-12-26 14:00:02.000 | 2019-12-26 | ------------ | -------- | -------------- |
+-------------+-----------+-------------------------+------------+--------------+----------+----------------+
| 1233 | O | 2019-12-28 22:00:01.000 | 2019-12-28 | ------------ | -------- | -------------- |
+-------------+-----------+-------------------------+------------+--------------+----------+----------------+
| 1233 | O | 2019-12-28 23:31:11.000 | 2019-12-28 | ------------ | -------- | -------------- |
+-------------+-----------+-------------------------+------------+--------------+----------+----------------+
| 1233 | O | 2019-12-29 15:08:10.000 | 2019-12-29 | ------------ | -------- | -------------- |
+-------------+-----------+-------------------------+------------+--------------+----------+----------------+
| 1233 | O | 2019-12-30 16:03:20.000 | 2019-12-30 | ------------ | -------- | -------------- |
+-------------+-----------+-------------------------+------------+--------------+----------+----------------+
| 1233 | O | 2020-01-02 06:52:18.000 | 2020-01-02 | ------------ | -------- | -------------- |
+-------------+-----------+-------------------------+------------+--------------+----------+----------------+
| 1233 | O | 2020-01-03 08:00:57.000 | 2020-01-03 | ------------ | -------- | -------------- |
+-------------+-----------+-------------------------+------------+--------------+----------+----------------+
| 1233 | O | 2020-01-04 06:40:11.000 | 2020-01-04 | ------------ | -------- | -------------- |
+-------------+-----------+-------------------------+------------+--------------+----------+----------------+
我目前得到的东西现在似乎可以工作,但是当时间戳有很大差异时,数据就会重复,例如,如果人时间戳 'O' (checktype) 在 左右12AM - 9AM 并在 10AM - 7PM 左右再次按下,记录将显示同一日期内的 2 个数据,没关系,我的主要问题是我们如何 select 仅在 LEFT JOIN
?
总而言之,如果我要使用 2019-12-25,是否有办法让 LEFT JOIN
仅根据记录输出 select 最接近的值14:50:00.000作为LEFT JOIN的基础,那么只有2019-12-25 14:51:57.000应该是select为 LEFT JOIN 编辑。我尝试使用 BETWEEN
和 DATEADD(-+HOUR)
,但它仍然 selecting 同一记录输出中的所有数据。有没有办法做到这一点?或者仅使用 LEFT JOIN
?
有没有办法修改这行代码来达到我的目标?
ON
t2.recordout BETWEEN DATEADD(HOUR,-(t0.noofhoursduty/2),t0.mergetimeoutorig) AND DATEADD(HOUR, 1,t0.mergetimeoutorig)
AND t2.badgenumber = t0.fingerscanno
AND t0.schedulename !='REST'
希望得到积极的回应,关于如何使用 LEFT JOIN 执行此操作一直困扰我很长时间。
使用 OUTER APPLY 而不是 LEFT JOIN 并且 select 仅第一个匹配行使用正确的顺序,类似这样:
...
OUTER APPLY (
select top(1) *
from (
SELECT
MAX(userinfo.badgenumber) AS badgenumber,
-- you current t2 subquery
) AS t2
where
t2.recordout BETWEEN DATEADD(HOUR,-(t0.noofhoursduty/2),t0.mergetimeoutorig) AND DATEADD(HOUR, 1,t0.mergetimeoutorig)
AND t2.badgenumber = t0.fingerscanno
AND t0.schedulename !='REST'
order by abs(datediff(minute, t0.mergetimeoutorig, t2.recordout )) desc
) t2
这不是一个有效的查询,因为我没有看到示例数据和 table 结构,但希望它有助于找到正确的方向。