2012-08-03 65 views
3

我正在構建一個基於位置的檢查插件的Web應用程序,有點像本地4square,但基於RFID標籤。如何找到哪兩行的時間戳彼此最接近?

無論如何,每個檢入存儲在MySQL表與用戶ID和檢測在作爲DATETIME列的時間。

現在我想顯示哪些用戶有不同站之間的最近登記時間。

說明:假設用戶A在21時43分12秒再次在21時43分19秒簽入,然後。他在7秒之內在車站之間移動。

有成千上萬簽入的數據庫,我怎麼寫SQL選擇有兩個最接近的入住時間的用戶?

+0

對於*快速*查找,您需要預先計算時間以便以前簽入並將其存儲在某個地方 – zerkms 2012-08-03 12:26:27

+0

您只需要用戶ID?或者你還想要相關的時間戳嗎? – MatBailie 2012-08-03 12:34:50

回答

1

真快解決方案會引入一些預先計算。就像存儲當前和前一次簽入之間的差異一樣。

在這種情況下,你會選擇在快速的方式需要什麼(只要你涵蓋索引列)。

不使用在這種情況下,預先計算將導致這將在笛卡爾式生產經營可怕查詢。

+0

我想我可以計算和存儲每個用戶的簽入與每一行之間的時差。你是這個意思嗎? – 2012-08-03 12:41:24

+0

嘿夥計,你能幫我一個忙,看看這[問題](http://stackoverflow.com/questions/11790402/pdo-refuses-to-delete-a-row-of-data-in-具體表)我的?它讓我難倒了一個混蛋: – Fluffeh 2012-08-03 12:41:32

+0

@MånsJonasson。不是真的,你只需計算相同用戶標識的後續**簽入之間的差異,這意味着你會在簽入表中添加一個新列:'差異' 。每次插入新簽入時,都會選擇最後一次簽入相同的用戶標識,並計算與最後一次簽入的數據差異。 – bpgergo 2012-08-03 14:30:21

1

試試這個:

select 
    a.id, 
    b.id, 
    abs(a.rfid-b.rfid) 
from 
    table1 a, 
    table1 a 
where 
    a.userID=b.userID 
    // and any other conditions to make it a single user 
group by 
    a.id, 
    b.id, 
    a.rfid, 
    b.rfid 
order by 
    abs(a.rfid-b.rfid) desc 
limit 1 
+0

爲每個用戶做一個交叉產品的確會非常糟糕。這與使用相關的子查詢相比如何? – MatBailie 2012-08-03 12:28:39

+0

'abs(a.rfid-b.rfid)'只要兩列不參與'group by'並且沒有聚合函數,就會返回不可預知的結果 – zerkms 2012-08-03 12:28:45

+0

謝謝,翻譯成我的行名,它看起來像這樣: 選擇 \t a.id, \t b.id, a.uid, b.uid, ABS(a.dateWhen-b.dateWhen) 從 rfid_actions一個, rfid_actions b 其中 一個。 uid = b.uid group by a.uid, b.uid order by 級ABS(a.dateWhen-b.dateWhen)遞減 限1 但結果很奇怪: 的ID(2)UID UID(2)ABS(a.date ... 6a42c540 \t 6a42c540 \t 0.000000 (當然,我還沒有得到stackoverflow降價) – 2012-08-03 12:32:07

0

首先,您需要用戶的索引,然後是時間戳。

其次,您需要使用相關的子查詢來查找「下一個時間戳」。

然後使用GROUP BY查找每個用戶的最小間隔。

SELECT 
    a.user_id, 
    MIN(TIMEDIFF(b.timestamp, a.timestamp)) AS min_duration, 
FROM 
    checkin  AS a 
INNER JOIN 
    checkin  AS b 
    ON b.user_id = a.user_id 
    AND b.timestamp = (SELECT MIN(timestamp) 
         FROM checkin 
         WHERE user_id = a.user_id 
          AND timestamp > a.timestamp) 
GROUP BY 
    a.user_id 
ORDER BY 
    min_duration 
LIMIT 
    1 

如果你想允許多個用戶使用相同的min_duration,我建議存儲結果(不LIMIT 1在臨時表中,然後搜索該表爲共享的最小持續時間的所有用戶。


根據數據量上,這可能是緩慢的。一個優化是緩存TIMEDIFF()的結果。每次記錄新的簽入時,也計算並存儲自上次簽入以來的持續時間,可能使用觸發器。通過預先計算,查詢變得更簡單,值可索引。

0

我的身影,你只需要計算兩個簽入之間的區別,如果他們是同一個人的兩個連續簽入。

create table test (
id int, 
person_id int, 
checkin datetime); 

insert into test (id, person_id, checkin) values (1, 1, now()); 
insert into test (id, person_id, checkin) values (2, 1, now()); 
insert into test (id, person_id, checkin) values (3, 2, now()); 
insert into test (id, person_id, checkin) values (4, 2, now()); 
insert into test (id, person_id, checkin) values (5, 1, now()); 
insert into test (id, person_id, checkin) values (6, 2, now()); 
insert into test (id, person_id, checkin) values (7, 1, now()); 


select * from (
    select a.*, 
    (select a.checkin - b.checkin 
    from test b where b.person_id = a.person_id 
    and b.checkin < a.checkin 
    order by b.checkin desc 
    limit 1 
) diff 
    from test a 
    where a.person_id = 1 
    order by a.person_id, a.checkin 
) tt 
where diff is not null 
order by diff asc; 
0
SELECT a.*, b.* 
FROM table_name AS a 
JOIN table_name AS b 
ON a.id != b.id 
ORDER BY TIMESTAMPDIFF(SECOND, a.checkin, b.checkin) ASC 
LIMIT 1 

應該這樣做。如上所述可能有點遲緩。