簡體   English   中英

Select 行,每個用戶的最近日期

[英]Select row with most recent date per user

我有一個用戶簽入和簽出時間的表(“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

我正在嘗試創建此表的視圖,該視圖將 output 僅提供每個用戶 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

這很接近,但並不完美。 我知道最后一個 group by 不應該在那里,但沒有它,它會返回最近的時間,但不是它的相對 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)

無需嘗試重​​新發明輪子,因為這是常見的每組最大 n 個問題 提出了非常好的解決方案

我更喜歡沒有子查詢的最簡單的解決方案(請參閱 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

如果您對空時間的行不感興趣,您可以在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 上的運行情況

如果您使用的是 MySQL 8.0 或更高版本,則可以使用窗口函數

詢問:

DBFiddle示例

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

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

好吧,這可能是黑客攻擊或容易出錯,但不知何故這也有效-

SELECT id, MAX(user) as user, MAX(time) as time, MAX(io) as io FROM lms_attendance GROUP BY id;

我做了同樣的事情,如下所示

SELECT t1.* FROM lms_attendance t1 WHERE t1.id in (SELECT max(t2.id) as id FROM lms_attendance t2 group BY t2.user)

這也會降低內存利用率。

謝謝。

我嘗試了一種對我有用的解決方案

    SELECT user, MAX(TIME) as time
      FROM lms_attendance
      GROUP by user
      HAVING MAX(time)

我有一張非常大的桌子,這里的所有其他建議都需要很長時間才能執行。 我想出了這個更快的hacky方法。 缺點是,如果 max(date) 行有該用戶的重復日期,它將返回它們。

SELECT * FROM mb_web.devices_log WHERE CONCAT(dtime, '-', user_id) in (
    SELECT concat(max(dtime), '-', user_id) FROM mb_web.devices_log GROUP BY user_id
)

可能您可以按用戶分組,然后按時間順序排序。 像下面這樣

  SELECT * FROM lms_attendance group by user order by time desc;

試試這個查詢:

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

這對我有用:

SELECT user, time FROM 
(
    SELECT user, time FROM lms_attendance --where clause
) AS T 
WHERE (SELECT COUNT(0) FROM table WHERE user = T.user AND time > T.time) = 0
ORDER BY user ASC, time DESC

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM