【问题标题】:MySql subselects and counts based on countsMySql根据计数进行子选择和计数
【发布时间】:2012-05-14 16:07:47
【问题描述】:

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

----------------     ----------------------------     -------------------------------
|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 应用程序,以防我提供更多选择。提前致谢。我喜欢堆栈,并希望能提供尽可能多的帮助。

【问题讨论】:

    标签: mysql select count temp-tables subquery


    【解决方案1】:

    这是一种方法

    创建一个临时表以获取最近的测量值

    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
    

    【讨论】:

      【解决方案2】:

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

      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)
      

      【讨论】:

      • 我实际上找到了一种不使用临时表的方法,并且我的网页从 2.5 到 2.2 的渲染速度提高了 0.3 秒。没什么大不了的,但是活跃的项目越多,花费的时间就越多。无论如何,使用上面的示例表,这是我开始工作的单个语句。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-07-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-09
      • 2017-02-14
      • 2012-03-05
      相关资源
      最近更新 更多