2

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

----------------     ----------------------------     -------------------------------
|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     |
-----------------------

所以,在这个例子中,苹果行没有被用来计数,因为它不是动物,蝙蝠也没有被用来计数,因为它的状态被设置为 no(意思是不测量),并且只使用了最近的测量值来确定计数。

我目前在我的实际使用中有一个解决方法,但它没有遵循良好的数据库规范化。在我的现实表中,我有一个 current_meas 列,当进行新的测量并将其输入测量表时,该列会更新。然后我只需要使用前两个表,我有一个 SELECT 语句,其中包含一堆嵌入的 SUM 语句,例如使用 IF 值在 0-9 之间。它给了我想要的东西,但是我的应用程序已经发展到这种便利在其他领域成为问题的地步。

所以,问题是,有没有一种更优雅的方法可以在一个语句中做到这一点?子选择?临时表?获得计数是该应用程序的核心。

这是一个基于 PHP5、MySQL5、JQuery 1.8 的 web 应用程序,以防给我更多选择。提前致谢。我喜欢堆栈,并希望能提供尽可能多的帮助。

4

2 回答 2

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);

更新

我让它在单个 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)
于 2012-05-15T13:50:39.100 回答
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
于 2012-05-14T16:26:44.830 回答