2015-02-24 56 views
0

背景使用日曆表,某個日期範圍內插入值

我上一個項目,我需要捕獲30天平均值的一些編號,然後使用該平均來確定,如果一些工作新的價值是異常的。就這個問題而言,我們可以假設我只需要10天的平均值,因爲解決方案可能類似。我目前有兩個表格:history其中包含我已經記錄了特定的id號碼的實際值,但可以有一些缺失的日子和calendar日期表,有我需要的30天的平均日子。

create table history (
    day  date not null, 
    id  bigint not null, 
    category int not null, 
    value int not null default '0', 
    primary key (day, id, category), 
    key category (category) 
); 

create table calendar (
    day date not null primary key 
); 

我想利用現有的數據,我在歷史表,並通過複製着以前的值或複製回前值中的丟失數據填充。例如,鑑於歷史表這樣的數據:

+------------+-----------+----------+-------+ 
| day  | id  | category | value | 
+------------+-----------+----------+-------+ 
| 2015-02-19 | 159253663 | 364 | 212 | 
| 2015-02-20 | 159253663 | 364 | 211 | 
| 2015-02-22 | 159253663 | 364 | 199 | 
| 2015-02-23 | 159253663 | 364 | 192 | 
| 2015-02-24 | 159253663 | 364 | 213 | 
+------------+-----------+--------+---------+ 

注:有是2015年2月21日

沒有進入,我想填補足夠的數據,這樣我可以計算10即將最早的價值(2015-02-19)複製回10天的價格範圍,然後用前一天的價格填寫缺失的2015-02-21價值。其結果將是這個(星紀念新添加的行):

+------------+-----------+----------+-------+ 
| day  | id  | category | value | 
+------------+-----------+----------+-------+ 
| 2015-02-14 | 159253663 | 364 | 212 | * 
| 2015-02-15 | 159253663 | 364 | 212 | * 
| 2015-02-16 | 159253663 | 364 | 212 | * 
| 2015-02-17 | 159253663 | 364 | 212 | * 
| 2015-02-18 | 159253663 | 364 | 212 | * 
| 2015-02-19 | 159253663 | 364 | 212 | 
| 2015-02-20 | 159253663 | 364 | 211 | 
| 2015-02-21 | 159253663 | 364 | 211 | * 
| 2015-02-22 | 159253663 | 364 | 199 | 
| 2015-02-23 | 159253663 | 364 | 192 | 
| 2015-02-24 | 159253663 | 364 | 213 | 
+------------+-----------+--------+---------+ 

未遂

我最初的想法是左連接到有我需要的日期範圍日曆表,當我做我得到的東西是這樣的:

select c.day, h.id, h.value 
from calendar c 
    left join history h using (day) 
where c.day between curdate() - interval 10 day and curdate(); 

+------------+-----------+----------+-----------+ 
| day  | id  | category | value | 
+------------+-----------+----------+-----------+ 
| 2015-02-14 |  NULL | NULL |  NULL | 
| 2015-02-15 |  NULL | NULL |  NULL | 
| 2015-02-16 |  NULL | NULL |  NULL | 
| 2015-02-17 |  NULL | NULL |  NULL | 
| 2015-02-18 |  NULL | NULL |  NULL | 
| 2015-02-19 | 159253663 | 364 |  212 | 
| 2015-02-19 | 159253690 | 364 |  222 | 
| 2015-02-20 | 159253663 | 364 |  211 | 
| 2015-02-20 | 159253690 | 364 |  221 | 
| 2015-02-21 |  NULL | NULL |  NULL | 
| 2015-02-22 | 159253663 | 364 |  199 | 
| 2015-02-22 | 159253690 | 364 |  209 | 
| 2015-02-23 | 159253663 | 364 |  192 | 
| 2015-02-23 | 159253690 | 364 |  202 | 
| 2015-02-24 | 159253663 | 364 |  213 | 
| 2015-02-24 | 159253690 | 364 |  213 | 
+------------+-----------+----------+-----------+ 

我不知道在哪裏可以從這個角度出發,因爲我需要每天爲每個不同編號的條目。如果這個連接失蹤,它只會返回一天。我正在尋找更好的方法。我希望儘可能在MySQL服務器上儘可能多地完成工作,但可以在編程上做一些事情。歡迎任何/所有想法或建議。

這裏是具有DDL定義,我與測試SQLFiddle:http://sqlfiddle.com/#!2/cc206/2

+1

「我想在MySQL服務器上儘可能多地推動工作......」除了首選項之外,還有其他理由嗎?在應用程序代碼中填寫空白通常要容易得多。 – tadman 2015-02-24 15:27:38

+0

@tadman只是首選項,我將使用哪一種解決方案效率最高 – 2015-02-24 15:29:28

+1

應用程序端解決方案的優點是您可以執行更復雜的日期計算,而無需依賴這些計算表的準確性。 MySQL的過程語言可能可以做到這一點,但由於沒有內在的測試框架,驗證它是否正確工作更加困難。 – tadman 2015-02-24 15:31:17

回答

1

下使用@變量和語句分配向後滾動值(和id):

SET @lastval = 0, @lastid = 0; 
SELECT c.day, @lastid := COALESCE(h.id,@lastid) id, @lastval := COALESCE(h.value,@lastval) VALUE, h.id id1,h.value v1 
FROM (SELECT DISTINCT c.day,h.id FROM history h, calendar c) c 
LEFT JOIN history h ON h.day = c.day AND h.id = c.id 
WHERE c.day BETWEEN CURDATE() - INTERVAL 10 DAY AND CURDATE() 
ORDER BY COALESCE(h.id,@lastid),c.day DESC 

子查詢似乎是必要的,從來不太確定爲什麼(有些做,有些不做)。

如果它看起來像結果順序錯誤,你可能必須添加:

SET optimizer_switch='block_nested_loop=off'; 

的語句塊嵌套循環優化前可以收集行時混亂與秩序MySQL使用。

+0

這似乎並沒有處理多個ID,它只是通過'2015-02-14' – 2015-02-24 15:53:28

+0

@Hunter McMillen複製回第一個ID - 不是根據我的結果,我確實需要編輯一下,你是否運行了最新版本。 – Giles 2015-02-24 15:57:02

+0

我做了http://sqlfiddle.com/#!2/cc206/25 – 2015-02-24 16:03:37