Выбор только ближайшего значения с помощью оператора LEFT JOIN и ON - PullRequest
1 голос
/ 12 января 2020

У меня проблема с тем, как это сделать, используя LEFTJOIN. Есть ли способ для LEFT JOIN и ON специально выбрать только ближайшее значение в запросе, где оно будет LEFT JOIN?

Например, у меня есть значения из запроса как эта таблица ниже, которая отсортирована на основе контрольной даты, и я отсортировал значение на основе 2019-12-25 . Я только хочу выбрать значение, наиболее близкое к 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' (контрольный тип) Примерно в 12:00 - 9:00 и повторное нажатие в 10:00 - 7:00 , запись покажет 2 данных в одну и ту же дату, и это нормально, мой главный проблема в том, как выбрать только ближайшее значение по сравнению с ним в LEFT JOIN?

Подводя итог, можно ли будет LEFT JOIN выбрать только самое близкое значение на основе записи, если я будет использоваться 2019-12-25 14: 50: 00.000 в качестве основы для LEFT JOIN, тогда для LEFT JOIN следует выбрать только 2019-12-25 14: 51: 57.000, Я попытался использовать BETWEEN и DATEADD(-+HOUR), но он все еще выбирает все данные в одной записи. Есть ли способ сделать это? или это правдоподобно, используя только 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.

1 Ответ

3 голосов
/ 12 января 2020

Использование OUTER APPLY вместо LEFT JOIN и выбор только первой подходящей строки, используя правильный порядок, что-то вроде этого:

...
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

Это трудновыполнимый запрос, поскольку я не вижу примеров данных и структур таблиц но, надеюсь, это поможет найти верное направление.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...