簡體   English   中英

SQL查詢與計算算法

[英]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.

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