[mysql] 사용자 당 가장 최근 날짜가있는 행 선택

다음과 같은 사용자의 체크인 및 체크 아웃 시간 테이블 ( “lms_attendance”)이 있습니다.

id  user    time    io (enum)
1   9   1370931202  out
2   9   1370931664  out
3   6   1370932128  out
4   12  1370932128  out
5   12  1370933037  in

“in”또는 “out”값을 제공하면서 사용자 ID 당 가장 최근 레코드 만 출력하는이 테이블의보기를 만들려고합니다.

id  user    time    io
2   9   1370931664  out
3   6   1370932128  out
5   12  1370933037  in

지금까지는 꽤 가깝지만 뷰가 하위 쿼리를 허용하지 않아 훨씬 더 어려워진다는 것을 깨달았습니다. 내가 얻은 가장 가까운 쿼리는 다음과 같습니다.

select
    `lms_attendance`.`id` AS `id`,
    `lms_attendance`.`user` AS `user`,
    max(`lms_attendance`.`time`) AS `time`,
    `lms_attendance`.`io` AS `io`
from `lms_attendance`
group by
    `lms_attendance`.`user`,
    `lms_attendance`.`io`

그러나 내가 얻는 것은 :

id  user    time    io
3   6   1370932128  out
1   9   1370931664  out
5   12  1370933037  in
4   12  1370932128  out

가깝지만 완벽하지는 않습니다. 마지막 그룹이 거기에 있으면 안된다는 것을 알고 있지만 그것이 없으면 가장 최근 시간을 반환하지만 상대 IO 값은 반환하지 않습니다.

어떤 아이디어? 감사!



답변

질문:

SQLFIDDLE 예

SELECT t1.*
FROM lms_attendance t1
WHERE t1.time = (SELECT MAX(t2.time)
                 FROM lms_attendance t2
                 WHERE t2.user = t1.user)

결과:

| ID | USER |       TIME |  IO |
--------------------------------
|  2 |    9 | 1370931664 | out |
|  3 |    6 | 1370932128 | out |
|  5 |   12 | 1370933037 |  in |

매번 작동하는 솔루션 :

SQLFIDDLE 예

SELECT t1.*
FROM lms_attendance t1
WHERE t1.id = (SELECT t2.id
                 FROM lms_attendance t2
                 WHERE t2.user = t1.user
                 ORDER BY t2.id DESC
                 LIMIT 1)


답변

이것은 그룹당 가장 큰 문제 이기 때문에 바퀴를 재발 명 할 필요가 없습니다 . 아주 좋은 해결책이 제시 됩니다.

하위 쿼리가없는 가장 단순한 솔루션 ( SQLFiddle, 업데이트 된 Justin ‘s 참조)을 선호합니다 (따라서 뷰에서 사용하기 쉽습니다).

SELECT t1.*
FROM lms_attendance AS t1
LEFT OUTER JOIN lms_attendance AS t2
  ON t1.user = t2.user
        AND (t1.time < t2.time
         OR (t1.time = t2.time AND t1.Id < t2.Id))
WHERE t2.user IS NULL

이것은 또한 동일한 그룹 내에서 동일한 가장 큰 값을 가진 두 개의 다른 레코드가있는 경우에도 작동합니다 (t1.time = t2.time AND t1.Id < t2.Id). 내가 여기서하는 일은 동일한 사용자의 두 레코드가 같은 시간을 가질 때 하나만 선택되도록하는 것입니다. 기준이 Id다른 것인지 여부는 실제로 중요하지 않습니다. 기본적으로 고유하다고 보장되는 모든 기준이 여기서 작동합니다.


답변

@TMS 답변을 기반으로 하위 쿼리가 필요하지 않기 때문에 좋아하지만 'OR'부분을 생략하면 이해하고 읽기가 훨씬 간단하고 충분할 것이라고 생각합니다 .

SELECT t1.*
FROM lms_attendance AS t1
LEFT JOIN lms_attendance AS t2
  ON t1.user = t2.user
        AND t1.time < t2.time
WHERE t2.user IS NULL

null 시간이있는 행에 관심이없는 경우 WHERE절 에서 필터링 할 수 있습니다 .

SELECT t1.*
FROM lms_attendance AS t1
LEFT JOIN lms_attendance AS t2
  ON t1.user = t2.user
        AND t1.time < t2.time
WHERE t2.user IS NULL and t1.time IS NOT NULL


답변

이미 해결되었지만 기록을 위해 또 다른 접근 방식은 두 개의 뷰를 만드는 것입니다.

CREATE TABLE lms_attendance
(id int, user int, time int, io varchar(3));

CREATE VIEW latest_all AS
SELECT la.user, max(la.time) time
FROM lms_attendance la
GROUP BY la.user;

CREATE VIEW latest_io AS
SELECT la.*
FROM lms_attendance la
JOIN latest_all lall
    ON lall.user = la.user
    AND lall.time = la.time;

INSERT INTO lms_attendance
VALUES
(1, 9, 1370931202, 'out'),
(2, 9, 1370931664, 'out'),
(3, 6, 1370932128, 'out'),
(4, 12, 1370932128, 'out'),
(5, 12, 1370933037, 'in');

SELECT * FROM latest_io;

SQL Fiddle에서 실제 작동을 보려면 여기를 클릭하십시오.


답변

select b.* from

    (select
        `lms_attendance`.`user` AS `user`,
        max(`lms_attendance`.`time`) AS `time`
    from `lms_attendance`
    group by
        `lms_attendance`.`user`) a

join

    (select *
    from `lms_attendance` ) b

on a.user = b.user
and a.time = b.time


답변

 select result from (
     select vorsteuerid as result, count(*) as anzahl from kreditorenrechnung where kundeid = 7148
     group by vorsteuerid
 ) a order by anzahl desc limit 0,1


답변

MySQL 8.0 이상에서는 Window 함수를 사용할 수 있습니다 .

질문:

DBFiddleExample

SELECT DISTINCT
FIRST_VALUE(ID) OVER (PARTITION BY lms_attendance.USER ORDER BY lms_attendance.TIME DESC) AS ID,
FIRST_VALUE(USER) OVER (PARTITION BY lms_attendance.USER ORDER BY lms_attendance.TIME DESC) AS USER,
FIRST_VALUE(TIME) OVER (PARTITION BY lms_attendance.USER ORDER BY lms_attendance.TIME DESC) AS TIME,
FIRST_VALUE(IO) OVER (PARTITION BY lms_attendance.USER ORDER BY lms_attendance.TIME DESC) AS IO
FROM lms_attendance;

결과:

| ID | USER |       TIME |  IO |
--------------------------------
|  2 |    9 | 1370931664 | out |
|  3 |    6 | 1370932128 | out |
|  5 |   12 | 1370933037 |  in |

Justin제안한 솔루션 을 사용하는 보다 내가 보는 이점 은 중간 뷰나 테이블 없이도 하위 쿼리에서도 사용자 별 (또는 ID 별 또는 기타별로) 최신 데이터가있는 행을 선택할 수 있다는 것입니다.

그리고 HANA를 실행하는 경우에도 ~ 7 배 더 빠릅니다 : D