2014-10-18 54 views
2

我有一個表,用於存儲關於在一段時間內添加到同一數據庫的不同表中的記錄數的統計信息。如何在單個查詢中使用連接和聚合函數更新表中的多個行

這是統計表的簡化模式。

+------+-------------+---------+-------+--------+ 
| id | programId | start | end | count | 
+------+-------------+---------+-------+--------+ 

IRL該表包含多個計數以及使用適度複雜的查詢計算的日期。每個programId將存在於表格中,end的值爲null,並且這是存儲給定程序的統計數據的位置。 cron作業運行以定期關閉時間片(即將end列設置爲有效日期)。下次統計數據更新時,將使用start值創建新程序行,並將end設置爲空。

這是消息表的簡化模式,它包含在統計表中彙總的數據。該表保存在統計表中彙總的數據。

+------+-------------+------------+--------+ 
| id | messageId | programId | time | 
+------+-------------+------------+--------+ 

我想通過單個查詢更新所有程序消息計數。以下查詢不起作用,因爲where語句中不允許使用聚合函數max。另外,我讀過有關在where子句中使用​​3210函數的警告。此外,它似乎錯誤具有相同的兩個表在單個查詢中反覆加入。我不是sql專家(顯然),但是這個查詢引發了各種各樣的紅旗 - 即使它有效,我也會在這裏張貼尋找改進方法。

UPDATE stats a 
INNER JOIN messages b on a.programId = b.programId 
SET a.numberReceived = 
    (SELECT COUNT(c.id) 
     FROM messages c LEFT JOIN stats d ON c.programId = d.programId 
     WHERE c.datetime >= coalesce(max(d.end), '1970-01-01 00:00:01) 
    ) 
WHERE end IS NULL 

的邏輯是隻計算如果存在上次關閉的時間片後已經到達的消息,否則算上所有給定的程序(即消息,如果這是第一次在節目中出現統計表)。

我試着將這個計數邏輯加入到觸發器中,但是,計算出的統計量比這個更多(這是一個簡化的例子),並且許多行一次插入到消息表中。結果是在一個after insert觸發器中包含此邏輯導致事務錯誤,導致插入失敗。

我知道我可以通過循環遍歷程序併發出很多針對數據庫的sql語句來編程,但認爲這可以在單個語句中完成。

+0

您是否可以添加一些樣本日期和預期結果?還修復您的查詢從我們沒有列號NumberReceived的問題。 – NMK 2014-10-18 05:39:07

回答

2

這裏是方法:

UPDATE 
    stats a 
INNER JOIN 
    (
    SELECT m.programId, count(*) as cnt 
    FROM 
     messages m 
    LEFT JOIN 
     (
     SELECT programId,max(end) as end 
     FROM 
      stats 
     WHERE end IS NOT NULL 
     GROUP BY programId 
     )as s 
    ON m.programId=s.programId 
    WHERE (s.end IS NULL OR m.datetime > s.end) 
    GROUP BY m.programId 
    ) b 
ON a.programId = b.programId 
SET a.numberReceived = b.cnt 
WHERE a.end IS NULL 

你需要一個子查詢s獲得最後結束日期爲每一個程序,然後使用它的結束日期之後過濾所有新郵件。最後通過programId得到子查詢b來計算新消息,然後你可以通過一個簡單的更新子句進行更新。

相關問題