2012-05-14 37 views
2

這是我的表結構的模型。三張桌子。MySql子選擇和計數基於計數

----------------  ----------------------------  ------------------------------- 
|possibilities |  |realities     |  |measurements     | 
|--------------|  |--------------------------|  |-----------------------------| 
|pid| category |  |rid | pid | item | status |  |mid | rid | meas | date  | 
|--------------|  |--------------------------|  |-----------------------------| 
|1 | animal |  |1 | 1 | dog | 1 (yes)|  |1 | 1 | 3 | 2012-01-01| 
|2 | vegetable|  |2 | 1 | fox | 1  |  |2 | 3 | 2 | 2012-01-05| 
|3 | mineral |  |3 | 1 | cat | 1  |  |3 | 1 | 13 | 2012-02-02| 
----------------  |4 | 2 | apple| 2 (no) |  |4 | 3 | 24 | 2012-02-15| 
        |5 | 1 | mouse| 1  |  |5 | 2 | 5 | 2012-02-16| 
        |7 | 1 | bat | 2  |  |6 | 6 | 4 | 2012-02-17| 
        ----------------------------  ------------------------------- 

我後是一個結果,將顯示我根據測量系列計數的範圍從「可能性」表中特定條目,其中相關的「現實」的狀態爲1(意思目前正在跟蹤),但唯一相關的測量是最近一次。

這是我正在尋找使用動物作爲可能性的示例結果。

----------------------- 
| 0-9 | 10-19 | 20-29 | 
|---------------------| 
| 2 | 1  | 1  | 
----------------------- 

所以,在這個例子中,蘋果排不是用來做計數,因爲它不是動物,也不是蝙蝠,因爲它的狀態設置爲無(意思是不計算),和只有最近的測量被用來確定計數。

我目前在我的真實世界使用中有一個解決方法,但它不遵循良好的數據庫規範化。在我的現實表中,我有一個current_meas列,當進行新的測量並輸入到測量表中時,該列將被更新。然後,我只需要使用前兩個表,並且我有一個SELECT語句和一些嵌入式SUM語句,使用IF值介於0-9之間的例子。它給了我正是我想要的,但是我的應用已經發展到了這種便利已成爲其他領域問題的地步。

所以,問題是,是否有一個更優雅的方式來做到這一點在一個聲明?子選擇?臨時表?獲取計數是應用程序的核心。

這是一個基於PHP5,MySQL5,JQuery 1.8的web應用程序,以防給我更多選擇。提前致謝。我喜歡這堆積木,並希望儘可能多地幫助我。

回答

0

這裏是我結束了基於兩個做建議的答案。

  1. 首先,我創建了一個生成的 現實表是基於一種可能性(動物),其 狀態爲1(是)一個臨時表。
  2. 其次,我創建了一個臨時表,它從第一個臨時表中生成一個 個體現實的表格,併爲每個臨時表格找到最近的一個測量值。
  3. 從第二張表中我做了一個選擇,它給出了範圍內 計數的細目。

當我只用一個臨時表進行試驗時,查詢每個可能性需要5-10秒。在我的真實世界中,我目前有30種可能性(一個腳本循環遍歷每一個併產生這些臨時表和選擇),超過1,000個實際情況(在任何一天有600個活動,每月增加100個活動),以及超過21,000個測量20-30每日補充)。那只是不適合我。因此,將其分解爲更小的池,以便將其縮減爲在3-4秒內運行的整個報告。

這裏是我的真實世界表和列名的MySQL東西。

//Delete the temporary tables in advance 
$delete_np_prod = 'DROP TABLE IF EXISTS np_infreppool'; 
mysql_query($delete_np_prod) or die ("Drop NP Prod Error " . mysql_error()); 
$delete_np_max = 'DROP TABLE IF EXISTS np_maxbrixes'; 
mysql_query($delete_np_max) or die ("Drop NP Max Error " . mysql_error()); 

//Make a temporary table to hold the totes of this product at North Plains that are active 
$create_np_prod_pool_statement = 'CREATE TEMPORARY TABLE np_infreppool 
SELECT inf_row_id FROM infusion WHERE formid = ' . $active_formids["formid"] . ' AND location = 1 AND status = 1'; 
mysql_query($create_np_prod_pool_statement) or die ("Prod Error " . mysql_error()); 

//Make a temporary table to hold the tote with its most recent brix value attached to it. 
$create_np_maxbrix_pool_statement = 'CREATE TEMPORARY TABLE np_maxbrixes 
SELECT b.inf_row_id AS inf_row_id, b.brix AS brix from brix b, np_infreppool pool WHERE b.inf_row_id = pool.inf_row_id AND b.capture_date = (SELECT max(capture_date) FROM brix WHERE inf_row_id = pool.inf_row_id)'; 
mysql_query($create_np_maxbrix_pool_statement) or die ("Brix Error " . mysql_error()); 

//Get the counts for slected form from NP 
$get_report_np = "SELECT 
     SUM(IF(brix BETWEEN 0 AND 4,1,0)) as '0-4', 
     SUM(IF(brix BETWEEN 5 AND 9,1,0)) as '5-9', 
     SUM(IF(brix BETWEEN 10 AND 14,1,0)) as '10-14', 
     SUM(IF(brix BETWEEN 15 AND 19,1,0)) as '15-19', 
     SUM(IF(brix BETWEEN 20 AND 24,1,0)) as '20-24', 
     SUM(IF(brix BETWEEN 25 AND 29,1,0)) as '25-29', 
     SUM(IF(brix BETWEEN 30 AND 34,1,0)) as '30-34', 
     SUM(IF(brix BETWEEN 35 AND 39,1,0)) as '35-39', 
     SUM(IF(brix BETWEEN 40 AND 44,1,0)) as '40-44', 
     SUM(IF(brix BETWEEN 45 AND 49,1,0)) as '45-49', 
     SUM(IF(brix BETWEEN 50 AND 54,1,0)) as '50-54', 
     SUM(IF(brix BETWEEN 55 AND 59,1,0)) as '54-49', 
     SUM(IF(brix BETWEEN 60 AND 64,1,0)) as '60-64', 
     SUM(IF(brix BETWEEN 65 AND 69,1,0)) as '65-69', 
     SUM(IF(brix >=70, 1, 0)) as 'Over 70' 
    FROM np_maxbrixes"; 
$do_get_report_np = mysql_query($get_report_np); 
$got_report_np = mysql_fetch_array($do_get_report_np); 

UPDATE

我得到它在一個單一的SELECT語句中工作,而無需使用臨時表和它的作品更快。使用上面的示例模式,這是它的外觀。

SELECT 
    SUM(IF(m.meas BETWEEN 0 AND 4,1,0)) as '0-4', 
    SUM(IF(m.meas BETWEEN 5 AND 9,1,0)) as '5-9', 
    SUM(IF(m.meas BETWEEN 10 AND 14,1,0)) as '10-14', 
    SUM(IF(m.meas BETWEEN 15 AND 19,1,0)) as '15-19', 
    SUM(IF(m.meas BETWEEN 20 AND 24,1,0)) as '20-24', 
    SUM(IF(m.meas BETWEEN 25 AND 29,1,0)) as '25-29', 
    SUM(IF(m.meas BETWEEN 30 AND 34,1,0)) as '30-34', 
    SUM(IF(m.meas BETWEEN 35 AND 39,1,0)) as '35-39', 
    SUM(IF(m.meas BETWEEN 40 AND 44,1,0)) as '40-44', 
    SUM(IF(m.meas BETWEEN 45 AND 49,1,0)) as '45-49', 
    SUM(IF(m.meas BETWEEN 50 AND 54,1,0)) as '50-54', 
    SUM(IF(m.meas BETWEEN 55 AND 59,1,0)) as '54-49', 
    SUM(IF(m.meas BETWEEN 60 AND 64,1,0)) as '60-64', 
    SUM(IF(m.meas BETWEEN 65 AND 69,1,0)) as '65-69', 
    SUM(IF(m.meas >=70, 1, 0)) as 'Over 70' 
FROM measurement m, realities r 
WHERE r.status = 1 AND r.pid = " . $_GET['pid'] . " AND r.rid = m.rid AND m.date = (SELECT max(date) FROM measurements WHERE rid = r.rid) 
+0

我實際上找到了一種不使用臨時表的方法,我的網頁從2.5到2.2的速度提高了0.3秒。沒有什麼大不了的,但是它所需要的更加活躍的項目。無論如何,使用上面的示例表格,這裏是我工作的單個語句。 – corbywan

0

這裏有一個方法

創建臨時表,以獲得最新測量

CREATE TEMPORARY TABLE RecentMeasurements 
SELECT * FROM Measurements m 
INNER JOIN (SELECT max(mid) max_id,date FROM Measurements GROUP BY DATE ORDER BY DATE) x 
ON x.max_id=m.mid 

那麼你查詢:

SELECT *, your counting logic 
FROM Realities 
WHERE status = 1 AND pid = 1 
INNER JOIN RecentMeasurements