2012-06-18 28 views
6

Cho phép nói rằng chúng tôi có một bảng cơ sở dữ liệu với hai cột, entry_time và giá trị. entry_time là dấu thời gian trong khi giá trị có thể là bất kỳ kiểu dữ liệu nào khác. Các hồ sơ tương đối nhất quán, được nhập vào khoảng x phút. Tuy nhiên, đối với nhiều x thời gian, một mục có thể không được thực hiện, do đó tạo ra một 'khoảng cách' trong dữ liệu.Phương pháp tìm lỗ hổng trong dữ liệu chuỗi thời gian trong MySQL?

Về mặt hiệu quả, cách tốt nhất để tìm kiếm những khoảng trống này ít nhất là thời gian Y (cả mới và cũ) với truy vấn?

+0

Làm cách nào để xác định khoảng cách? Bạn có một giới hạn khó khăn về thời gian có thể trôi qua giữa các đầu vào không? –

+0

Biến Y. Quên để xác định điều đó. – TheDog

Trả lời

15

Để bắt đầu, hãy cho chúng tôi tóm tắt số lượng mục nhập theo giờ trong bảng của bạn.

SELECT CAST(DATE_FORMAT(entry_time,'%Y-%m-%d %k:00:00') AS DATETIME) hour, 
     COUNT(*) samplecount 
    FROM table 
GROUP BY CAST(DATE_FORMAT(entry_time,'%Y-%m-%d %k:00:00') AS DATETIME) 

Bây giờ, nếu bạn đăng nhập một vài thứ sáu phút (mười lần một giờ), tất cả giá trị mẫu của bạn phải là mười. Biểu thức này: CAST(DATE_FORMAT(entry_time,'%Y-%m-%d %k:00:00') AS DATETIME) trông có lông nhưng nó chỉ đơn giản là cắt ngắn các dấu thời gian của bạn thành giờ mà chúng xuất hiện bằng cách lấy số phút và giây ra.

Điều này có hiệu quả hợp lý và sẽ giúp bạn bắt đầu. Nó rất hiệu quả nếu bạn có thể đặt một chỉ mục trên cột entry_time của bạn và hạn chế truy vấn của bạn, ví dụ, các mẫu của ngày hôm qua như được hiển thị ở đây.

SELECT CAST(DATE_FORMAT(entry_time,'%Y-%m-%d %k:00:00') AS DATETIME) hour, 
     COUNT(*) samplecount 
    FROM table 
WHERE entry_time >= CURRENT_DATE - INTERVAL 1 DAY 
    AND entry_time < CURRENT_DATE 
GROUP BY CAST(DATE_FORMAT(entry_time,'%Y-%m-%d %k:00:00') AS DATETIME) 

Nhưng không thể phát hiện toàn bộ số giờ đi kèm với các mẫu bị thiếu. Nó cũng là một chút nhạy cảm với jitter trong mẫu của bạn. Tức là, nếu mẫu hàng đầu của bạn đôi khi sớm hơn nửa giây (10:59:30) và đôi khi trễ nửa giây (11:00:30) số lượng tóm tắt hàng giờ của bạn sẽ bị tắt. Vì vậy, điều tóm tắt giờ này (hoặc tóm tắt ngày, hoặc tóm tắt phút, vv) không phải là chống đạn.

Bạn cần truy vấn tự tham gia để hoàn thành công việc một cách hoàn hảo; đó là một chút của một hairball và không gần như là hiệu quả.

Hãy bắt đầu bằng cách tạo cho mình một bảng ảo (truy vấn phụ) như thế này với các mẫu được đánh số. (Đây là một nỗi đau trong MySQL, một số DBMS đắt tiền khác làm cho nó dễ dàng hơn. Không có vấn đề gì.)

SELECT @sample:[email protected]+1 AS entry_num, c.entry_time, c.value 
    FROM (
     SELECT entry_time, value 
     FROM table 
     ORDER BY entry_time 
    ) C, 
    (SELECT @sample:=0) s 

Bảng ảo nhỏ này cung cấp entry_num, entry_time, value.

Bước tiếp theo, chúng tôi tự tham gia.

SELECT one.entry_num, one.entry_time, one.value, 
     TIMEDIFF(two.value, one.value) interval 
    FROM (
    /* virtual table */ 
) ONE 
    JOIN (
    /* same virtual table */ 
) TWO ON (TWO.entry_num - 1 = ONE.entry_num) 

Điều này xếp hàng hai bảng tiếp theo được bù trừ bởi một mục duy nhất, được điều chỉnh bởi mệnh đề ON của JOIN.

Cuối cùng, chúng tôi chọn các giá trị từ bảng này với số lớn hơn ngưỡng của bạn interval và có thời gian của mẫu ngay trước các giá trị bị thiếu.

Hơn tất cả truy vấn tự tham gia là điều này. Tôi đã nói với bạn đó là một viên bi.

SELECT one.entry_num, one.entry_time, one.value, 
     TIMEDIFF(two.value, one.value) interval 
    FROM (
    SELECT @sample:[email protected]+1 AS entry_num, c.entry_time, c.value 
     FROM (
      SELECT entry_time, value 
      FROM table 
      ORDER BY entry_time 
    ) C, 
     (SELECT @sample:=0) s 
) ONE 
    JOIN (
    SELECT @sample2:[email protected]+1 AS entry_num, c.entry_time, c.value 
     FROM (
      SELECT entry_time, value 
      FROM table 
      ORDER BY entry_time 
    ) C, 
     (SELECT @sample2:=0) s 
) TWO ON (TWO.entry_num - 1 = ONE.entry_num) 

Nếu bạn phải làm điều này trong sản xuất trên một bảng lớn, bạn có thể muốn làm điều đó cho một tập hợp con dữ liệu của bạn. Ví dụ, bạn có thể làm điều đó mỗi ngày cho các mẫu của hai ngày trước đó. Điều này sẽ rất hiệu quả, và cũng sẽ đảm bảo bạn không bỏ qua bất kỳ mẫu bị thiếu nào vào lúc nửa đêm. Để làm điều này, các bảng ảo nhỏ của bạn sẽ trông như thế này.

SELECT @sample:[email protected]+1 AS entry_num, c.entry_time, c.value 
    FROM (
     SELECT entry_time, value 
     FROM table 
     ORDER BY entry_time 
     WHERE entry_time >= CURRENT_DATE - INTERVAL 2 DAY 
      AND entry_time < CURRENT_DATE /*yesterday but not today*/ 
    ) C, 
    (SELECT @sample:=0) s 
+0

Cảm ơn bạn rất nhiều vì giải pháp này, mặc dù tôi bị nhầm lẫn về chính xác @sample: = @ sample + 1 không – TheDog

+0

Biến '@ sample' này theo dõi số hàng. Lưu ý rằng nó được khởi tạo trong '(SELECT @sample: = 0)' và tăng lên cho mỗi hàng của bảng. Nếu bạn có hàng chục ngàn đô la để trả cho Oracle, bạn chỉ có thể nói ROWNUM, nhưng đây là hack MySQL để làm điều tương tự. Arcane, eh? –

+0

+1 để được giải thích từng bước – kirugan

1

Cách rất hiệu quả để thực hiện điều này là với quy trình được lưu trữ sử dụng con trỏ.Tôi nghĩ điều này đơn giản và hiệu quả hơn các câu trả lời khác.

Quy trình này tạo một con trỏ và lặp lại nó thông qua các bản ghi ngày giờ bạn đang kiểm tra. Nếu có một khoảng trống nhiều hơn những gì bạn chỉ định, nó sẽ viết khoảng trống bắt đầu và kết thúc với một bảng.

CREATE PROCEDURE findgaps() 
    BEGIN  
    DECLARE done INT DEFAULT FALSE; 
    DECLARE a,b DATETIME; 
    DECLARE cur CURSOR FOR SELECT dateTimeCol FROM targetTable 
          ORDER BY dateTimeCol ASC; 
    DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;  
    OPEN cur;  
    FETCH cur INTO a;  
    read_loop: LOOP 
     SET b = a; 
     FETCH cur INTO a; 
     IF done THEN 
      LEAVE read_loop; 
     END IF;  
     IF DATEDIFF(a,b) > [range you specify] THEN 
      INSERT INTO tmp_table (gap_begin, gap_end) 
      VALUES (a,b); 
     END IF; 
    END LOOP;   
    CLOSE cur;  
    END; 

Trong trường hợp này, giả định rằng 'tmp_table' tồn tại. Bạn có thể dễ dàng định nghĩa điều này như là một bảng tạm thời trong thủ tục, nhưng tôi đã bỏ nó ra khỏi ví dụ này.

Các vấn đề liên quan