web-dev-qa-db-ja.com

ユーザーごとに最新の日付を含む行を選択してください

私はこのように見えるユーザーのチェックインとアウトの時間の表( "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

このテーブルのビューを作成して、ユーザーIDごとに最新のレコードのみを出力するようにしながら、 "in"または "out"の値を指定します。

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

どれが近いですか、しかし完璧ではありません。最後のgroup byはそこにあってはいけないことを私は知っていますが、それがなければ、それは最新の時間を返しますが、それは相対的なIO値ではありません。

何か案は?ありがとうございます。

111
Keith

クエリ:

SQLFIDDLEExample

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 |

毎回動作するつもりの解決策:

SQLFIDDLEExample

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)
171
Justin

これは一般的なので、車輪の再発明を試みる必要はありません グループあたりの最大数の問題 。とても良い 解決策が提示されている

私は副問い合わせなしで最も単純化された解決法( SQLFiddleを見てください、Justinのものを更新しました を参照してください)(ビューで使うのが簡単です):

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

これは、同じグループ内に同じ最大値を持つ2つの異なるレコードがある場合にも機能します - (t1.time = t2.time AND t1.Id < t2.Id)のトリックのおかげで。私がここでやっているのは、同じユーザーの2つのレコードが同じ時間を持つ場合に、必ず1つだけが選択されるようにすることです。基準がIdであるかそれ以外のものであるかは実際には問題ではありません。基本的に一意であることが保証されている基準であれば、ここで仕事ができます。

66
TMS

@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
5
user1792210

すでに解決されていますが、記録のためだけに、もう2つのアプローチは2つのビューを作成することです。

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 で実際に動作しているのを見るにはここをクリックしてください。

4
davmos

このクエリを試してください。

  select id,user, max(time), io 
  FROM lms_attendance group by user;
1
Sugan

OK

SELECT id, MAX(user) as user, MAX(time) as time, MAX(io) as io FROM lms_attendance GROUP BY id;
0
kev
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
0
chetan
 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