[英]SQL query with calculating algorithm
編寫SQL語句以獲得某些結果時遇到一些問題。 這是我的示例數據:
對於相同的ID,如果第二個開始時間減去第一個結束時間小於45分鍾,它將顯示第一個start_loc和第二個end_loc。 目前我的SQL是:
SELECT start_loc, end_loc FROM Table WHERE end_time - start_time <= 45 GROUP BY ID;
它返回兩行結果: 第一行:202,208; 第二排112,102
期望的結果應該是65,102和第二排229,208
任何指南? 提前致謝。
編輯
請注意,這比我最初想的要復雜得多。 為了它的樂趣,我用SQL解決了它。 如果性能是一個問題,請考慮在應用程序級別而不是在數據庫級別上解決它。
這里是。 首先,我創建了一個有助於簡化最終查詢的表:
create table tmp_foo as
select
sq.*,
@rn := @rn + 1 as row_number,
@gn := if(@prevless != less45, @gn + 1, @gn) as gn,
@prevless := less45
from (
select
t.*,
if(time_to_sec(timediff(start_time, @prevtime)) <= 45 * 60, 1, 0) as less45,
@prevtime := end_time
from
transaction t
, (select @prevtime := (select min(start_time) from transaction)) inner_var_init
order by start_time, end_time
) sq
, (select @gn := 0, @prevless := null, @rn := 0) outer_var_init
order by start_time, end_time;
請注意,此表沒有任何索引。 如果性能成為問題,您可能想要創建一些。 並在原來的桌子上:)
一點解釋:
首先我們初始化變量
, (select @prevtime := (select min(start_time) from transaction)) inner_var_init
使用@prevtime變量,我們訪問上一行。 這就是為什么select子句中的順序很重要的原因。 這里
if(time_to_sec(timediff(start_time, @prevtime)) <= 45 * 60, 1, 0) as less45,
@prevtime := end_time
在@prevtime的第一行中保存前一行的值。 在第二行中,將當前行的值分配給@prevtime變量。 在第一行,我們檢查您的情況,如果行之間的時間超過45分鍾。 如果是,返回1,否則返回0.我們需要這個,所以我們以后可以識別哪些行屬於一起。 請注意,子查詢中的order by子句也很重要。 不要“優化”它。
現在我們有了這個,我們在外部查詢上使用相同的邏輯。
@rn := @rn + 1 as row_number,
@gn := if(@prevless != less45, @gn + 1, @gn) as gn,
@prevless := less45
在第一行中,我們只是實現了一個不斷增加的(行)數字。 我們需要這個,所以我們后來知道屬於哪一行的最小值和最大值。
第二行是“組”編號(gn)。 每次其值發生變化時,數量都會增加。 我們需要這個,所以我們以后可以將表連接到自身並獲得最小值和最大值。
我為這一切創建了一個表,因為我們必須在最終查詢中使用它4次。 我不確定,如果優化器識別出,它只需要執行一次。 由於使用了變量,我對此表示懷疑。 您可以通過用(<the_whole_select_to_create_tmp_foo>)
替換最終查詢中的tmp_foo
來檢查這一點。 然后將EXPLAIN EXTENDED
放在最后查詢的第一個SELECT
前面。 執行它並發出SHOW WARNINGS;
然后。 這將顯示MySQL執行的真實查詢。
如果您想了解有關用戶定義變量的更多信息,請參閱手冊條目 。
無論如何,這是最后的查詢:
select
tmin.start_time,
tmax.end_time,
tmin.start_loc,
tmax.end_loc
from tmp_foo tmin
inner join tmp_foo tmax ON tmin.gn = tmax.gn
where tmin.row_number = (select min(row_number) from tmp_foo t where tmin.gn = t.gn)
and tmax.row_number = (select max(row_number) from tmp_foo t where tmin.gn = t.gn)
;
這是相當自我解釋的。 將表連接到自身並獲取最小值和最大值。 如果你想知道我們為什么不使用group by
和aggregate函數。 這是手冊中的一個優秀條目: 行保持某一列的最大組
最后......
基於此示例數據:
+------+------------+----------+-----------+---------+
| id | start_time | end_time | start_loc | end_loc |
+------+------------+----------+-----------+---------+
| 1 | 09:30:45 | 09:40:45 | 11 | 12 |
| 1 | 09:50:45 | 09:55:45 | 15 | 13 |
| 1 | 10:55:45 | 11:20:45 | 16 | 19 |
| 1 | 11:30:45 | 11:40:45 | 8 | 7 |
+------+------------+----------+-----------+---------+
結果是:
+------------+----------+-----------+---------+
| start_time | end_time | start_loc | end_loc |
+------------+----------+-----------+---------+
| 09:30:45 | 09:55:45 | 11 | 13 |
| 10:55:45 | 11:20:45 | 16 | 19 |
| 11:30:45 | 11:40:45 | 8 | 7 |
+------------+----------+-----------+---------+
看到它在sqlfiddle中工作
使用下面的mysql查詢來獲得所需的結果。
SELECT start_loc, end_loc FROM Table WHERE TIME_TO_SEC(TIMEDIFF(end_time,start_time))/60 <= 45 GROUP BY ID;
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.