MySql根据计数进行子选择和计数

时间:2012-05-14 16:07:48

标签: mysql select count temp-tables subquery

这是我的表结构的模型。三张桌子。

----------------     ----------------------------     -------------------------------
|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语句,其中包含一堆使用IF的嵌入式SUM语句,例如,该值介于0-9之间。它给了我我想要的东西,但是我的应用程序已经发展到这样的便利已成为其他领域的问题。

所以,问题是,在一个声明中有更优雅的方法吗?子选择?临时表?获得计数是应用程序的核心所在。

这是一个基于PHP5,MySQL5,基于JQuery 1.8的webapp,以防万一给我一些选择。提前致谢。我喜欢这个堆栈,希望尽可能多地帮助我。

2 个答案:

答案 0 :(得分: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

答案 1 :(得分:0)

根据建议的两个答案,这是我最终做的事情。

  1. 首先,我创建了一个生成表的临时表 基于一种可能性(动物)及其基础的现实 状态为1(是)。
  2. 其次我创建了一个生成表的临时表 来自第一个临时表的个体现实,并找到最多 每个人最近的测量结果。
  3. 从第二张表中我做了一个选择,它给出了我的细分 计算范围。
  4. 当我尝试使用一个临时表时,查询每个可能性需要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);
    

    <强>更新

    我让它在单个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)