获取两个数组之间的差异

3
我有两个搜索查询-一个将显示过去7天的内容。另一个将显示2周前的内容。 两者都可以正常工作。然而,我想从第一个查询结果中获取与第二个查询结果的差异。然后以带有差异的方式显示第一个查询结果。
$result_account = $db->query("
SELECT nid
     , COUNT(cat) AS qty
     , dte
     , descript
     , cat
     , name
     , user 
  FROM client_note AS cn 
  JOIN client_note_tag_items AS cnti 
    ON cnti.note_id = cn.nid 
  JOIN client_note_tags AS cnt 
    ON cnt.tag_id = cnti.tag_id 
 WHERE dte >= DATE_SUB(CURDATE(), INTERVAL 7 DAY) 
   AND name NOT LIKE 'Resolution%' 
 GROUP 
    BY cat 
 ORDER 
    BY qty DESC 
 LIMIT 5
");
       if($count_account = $result_account->num_rows) {
               while($row = $result_account->fetch_object()){

          echo "<tr>";
          echo "<td><h6>".$row->cat."</h6></td><td><h3 class='text-primary'>".$row->qty."</h3></td>";
          echo "</tr>";
          }
       }

$result_previous = $db->query("SELECT nid, COUNT(cat) AS qty, dte, descript, cat, name, user FROM client_note AS cn JOIN client_note_tag_items AS cnti ON cnti.note_id = cn.nid JOIN client_note_tags AS cnt ON cnt.tag_id = cnti.tag_id WHERE (dte BETWEEN DATE_SUB(CURDATE(), INTERVAL 21 DAY) AND DATE_SUB(CURDATE(), INTERVAL 14 DAY)) AND name NOT LIKE 'Resolution%' GROUP BY cat ORDER BY qty DESC LIMIT 5");
    if($count_previous = $result_previous->num_rows) {
            while($row_p = $result_previous->fetch_object()){

          echo "<tr>";  
          echo "<td><h6>".$row_p->cat."</h6></td><td><h3 class='text-primary'>".$row_p->qty."</h3></td>";
          echo "</tr>";


            }
    }

第一个查询的结果如下:

Category   - Qty
Baseball   - 45
Football   - 33
Soccer     - 21
Hockey     - 7
Basketball - 3

第二个查询将导致:
Category   - Qty
Basketball - 38
Soccer     - 28
Hockey     - 16
Football   - 12
Baseball   - 12

现在我想要像这样显示它。
Category   - Qty Difference
Baseball   - 45  +33
Football   - 33  +21
Soccer     - 21  -7
Hockey     - 7   -9
Basketball - 3   -35

如果一个查询中存在一个“运动”,而另一个查询中不存在,您希望它从结果中省略还是假定为零并相应计算? - TheMouseMaster
两个查询都将包含所有类别 - 但我只显示前5个。 - adiquet
从(第一个查询)a左连接(第二个查询)b,其中一些b条件等于一些a条件。选择a.*,a.something - b.something。 - Strawberry
1
如果上周的“前五大运动”与下周的“前五大运动”不同,会发生什么情况?如果开始比较实际存在但未在其中一个列表中显示的数字,则数学可能会变得有些奇怪。 - TheMouseMaster
@adiquet 你说你只显示前5个。什么是前5个?第一个查询的前5个?第二个查询的前5个?还是差异的前5个?根据你在这里回答我的问题,我可以更新我的答案。 - Cornel Raiu
4个回答

2

可以在单个SQL查询中使用条件聚合来比较不同时间段的相同数据:

最初的回答:

SELECT 
    cat, 
    SUM(IF(dte >= d.start1, 1, 0)) AS qty, 
    SUM(IF(dte >= d.start1, 1, 0)) - SUM(IF(dte < d.end2, 1, 0)) AS Difference, 
FROM 
    (SELECT DATE_SUB(CURDATE(), INTERVAL 7 DAY) start1, DATE_SUB(CURDATE(), INTERVAL 14 DAY) end2) as d
    CROSS JOIN client_note AS cn 
    JOIN client_note_tag_items AS cnti ON cnti.note_id = cn.nid 
    JOIN client_note_tags AS cnt ON cnt.tag_id = cnti.tag_id 
WHERE
    dte >= DATE_SUB(CURDATE(), INTERVAL 21 DAY) 
    AND name NOT LIKE 'Resolution%' 
GROUP BY cat 
ORDER BY qty DESC 
LIMIT 5

注:

  • 第一个子查询只是一个快捷方式,避免重复输入相同的DATE_SUB...表达式
  • 我删除了在输出中没有使用的列
  • 你需要在查询中正确地为列命名别名;现在很难确定哪个列属于哪个表
  • 推荐(在非古老的MySQL版本中必须)将所有非聚合列放入GROUP BY子句中
  • 没有提供示例数据 => 无法测试查询

PS:正如cornel.raiu所评论的那样,只有在不需要单独输出结果再将它们组合在一起时,这种方法才有意义(否则,你最终会运行3个SQL查询,这可能不是最优选择)。

最初的回答:这个查询包含一个子查询,用于简化表达式的输入,并排除了一些未使用的列。为了更好地对查询结果进行归纳,建议将非聚合列都放入GROUP BY子句中。请注意,此查询没有提供样本数据,因此无法进行测试。此外,如果需要单独输出结果再将其组合在一起,则此方法可能不是最优选择。同时也需要正确为列命名别名,以便更好地区分属于哪个表的列。

这很不错。我唯一看到的是他可能也想将不同查询的结果分别输出。这就是为什么我在我的回答中没有将它合并成一个查询的原因。 - Cornel Raiu
1
@cornel.raiu:是的,你说得对。我更新了我的回答以明确提到这一点。 - GMB
1
谢谢您提供的这份资料。 - adiquet

0

将第一组数字存储在两个关联数组中,然后在第二个循环中计算差异。

$initial = [];
$diff = [];
$result_account = $db->query("SELECT nid, COUNT(cat) AS qty, dte, descript, cat, name, user FROM client_note AS cn JOIN client_note_tag_items AS cnti ON cnti.note_id = cn.nid JOIN client_note_tags AS cnt ON cnt.tag_id = cnti.tag_id WHERE `dte` >= DATE_SUB(CURDATE(), INTERVAL 7 DAY) AND name NOT LIKE 'Resolution%' GROUP BY cat ORDER BY qty DESC LIMIT 5");
   if($count_account = $result_account->num_rows) {
           while($row = $result_account->fetch_object()){

      echo "<tr>";
      echo "<td><h6>".$row->cat."</h6></td><td><h3 class='text-primary'>".$row->qty."</h3></td>";
      echo "</tr>";
      $initial[$row->cat] = $row->qty; //remember 1st results
      $diff[$row->cat] = $row->qty; //to be used
      }
   }

$result_previous = $db->query("SELECT nid, COUNT(cat) AS qty, dte, descript, cat, name, user FROM client_note AS cn JOIN client_note_tag_items AS cnti ON cnti.note_id = cn.nid JOIN client_note_tags AS cnt ON cnt.tag_id = cnti.tag_id WHERE (dte BETWEEN DATE_SUB(CURDATE(), INTERVAL 21 DAY) AND DATE_SUB(CURDATE(), INTERVAL 14 DAY)) AND name NOT LIKE 'Resolution%' GROUP BY cat ORDER BY qty DESC LIMIT 5");
if($count_previous = $result_previous->num_rows) {
        while($row_p = $result_previous->fetch_object()){

      echo "<tr>";  
      echo "<td><h6>".$row_p->cat."</h6></td><td><h3 class='text-primary'>".$row_p->qty."</h3></td>";
      echo "</tr>";
      $diff[$row_p->cat] -= $row_p->qty; 

        }
}
//now print the initial qty and the difference
$cats = array_keys($diff);
for($i=0; $i<sizeof($cats); $i++){
    echo "<tr>";
    echo "<td><h6>".$cats[$i]."</h6></td>";
    $first = $initial[$cats[$i]];
    echo "<td><h3 class='text-primary'>$first</h3></td>"
    $d = $diff[$cats[$i]];
    $sign = $d < 0 ? "-" : "+";
    echo "<td><h3 class='text-primary'>$sign $d</h3></td>";
    echo "<tr>";
}

在这里的第二个查询循环中,此代码$diff[$row->cat] -= $row->qty;将会返回一个"Trying to get property 'cat' of non-object"的错误。在第二个查询循环中,你没有一个$row,而是有一个$row_p - Cornel Raiu

0
我会创建另一个数组,以键值对的方式保存第一个查询中的值,并在下一个查询中从相应条目中减去该值。
我认为这是使用两个查询最简单和最快的方法。
注意:我没有测试过这段代码。
注意2:我假设第一个类别中缺少的运动将计为0。
注意3:我编写的代码仅用于显示计算差异的方法。如果需要更新以提供您所需的完全相同的输出,请告诉我。
$results = array();

$result_account = $db->query("SELECT nid, COUNT(cat) AS qty, dte, descript, cat, name, user FROM client_note AS cn JOIN client_note_tag_items AS cnti ON cnti.note_id = cn.nid JOIN client_note_tags AS cnt ON cnt.tag_id = cnti.tag_id WHERE `dte` >= DATE_SUB(CURDATE(), INTERVAL 7 DAY) AND name NOT LIKE 'Resolution%' GROUP BY cat ORDER BY qty DESC LIMIT 5");
   if($count_account = $result_account->num_rows) {
      while($row = $result_account->fetch_object()){

        //output this query results here
        $results[$row->cat] = $row->qty;
      }
   }

$result_previous = $db->query("SELECT nid, COUNT(cat) AS qty, dte, descript, cat, name, user FROM client_note AS cn JOIN client_note_tag_items AS cnti ON cnti.note_id = cn.nid JOIN client_note_tags AS cnt ON cnt.tag_id = cnti.tag_id WHERE (dte BETWEEN DATE_SUB(CURDATE(), INTERVAL 21 DAY) AND DATE_SUB(CURDATE(), INTERVAL 14 DAY)) AND name NOT LIKE 'Resolution%' GROUP BY cat ORDER BY qty DESC LIMIT 5");
if($count_previous = $result_previous->num_rows) {
    while($row_p = $result_previous->fetch_object()){

      //output this query results here
      $results[$row_p->cat] = ((isset($results[$row_p->cat])) ? $results[$row_p->cat] : 0 ) - $row_p->qty;
    }
}


foreach( $results as $key => $result) {
  echo "<tr>";  
  echo "<td><h6>".$key."</h6></td><td><h3 class='text-primary'>".$result."</h3></td>";
  echo "</tr>";
}

更新 - 显示第一周和其差异

你可以尝试这个。我摆脱了foreach,只使用查询循环完成了所有操作。

注意:再次强调,这是未经测试的代码。

$results = array();

$result_account = $db->query("SELECT nid, COUNT(cat) AS qty, dte, descript, cat, name, user FROM client_note AS cn JOIN client_note_tag_items AS cnti ON cnti.note_id = cn.nid JOIN client_note_tags AS cnt ON cnt.tag_id = cnti.tag_id WHERE `dte` >= DATE_SUB(CURDATE(), INTERVAL 7 DAY) AND name NOT LIKE 'Resolution%' GROUP BY cat ORDER BY qty DESC LIMIT 5");

$result_previous = $db->query("SELECT nid, COUNT(cat) AS qty, dte, descript, cat, name, user FROM client_note AS cn JOIN client_note_tag_items AS cnti ON cnti.note_id = cn.nid JOIN client_note_tags AS cnt ON cnt.tag_id = cnti.tag_id WHERE (dte BETWEEN DATE_SUB(CURDATE(), INTERVAL 21 DAY) AND DATE_SUB(CURDATE(), INTERVAL 14 DAY)) AND name NOT LIKE 'Resolution%' GROUP BY cat ORDER BY qty DESC");
if($count_previous = $result_previous->num_rows) {
    while($row_p = $result_previous->fetch_object()){

      //output this query results here
      $results[$row_p->cat] = $row_p->qty;
    }
}

if($count_account = $result_account->num_rows) {
    while($row = $result_account->fetch_object()){

        $difference = $row->qty - ((isset($results[$row->cat])) ? $results[$row->cat] : 0 );

        echo "<tr>";  
        echo "<td><h6>".$row->cat."</h6></td><td><h3 class='text-primary'>".$row->qty."</h3></td><td><h3 class='text-primary'>".$difference."</h3></td>";
        echo "</tr>";
    }
}

1
以这种方式操作会在我的端口上导致 PHP 错误,错误信息为“尝试获取非对象的属性 'cat',位于第 15 行”,可能是因为它没有嵌套,无法找到该变量。 - adiquet
这个可以运行 -- 但是我该如何显示当前周、查询1,然后在旁边显示差异呢? - adiquet
在第13行出现了未定义变量:row。while循环只引用了row_p。我更新了$results[$row_p->cat] = $row_p->qty;,看起来可以工作。我会把它放到我的代码中并进行测试。 - adiquet
已更新。抱歉 :) - Cornel Raiu
@adiquet 现在检查一下。我在第二个查询中删除了 limit 5,这样它就可以从上周拉取所有内容,然后在实际显示的 while 循环中将提取所需的值并进行计算。 - Cornel Raiu
显示剩余4条评论

0

你可以做到这个

$result_account = $db->query("
SELECT nid
     , COUNT(cat) AS qty
     , dte
     , descript
     , cat
     , name
     , user 
  FROM client_note AS cn 
  JOIN client_note_tag_items AS cnti 
    ON cnti.note_id = cn.nid 
  JOIN client_note_tags AS cnt 
    ON cnt.tag_id = cnti.tag_id 
 WHERE dte >= DATE_SUB(CURDATE(), INTERVAL 7 DAY) 
   AND name NOT LIKE 'Resolution%' 
 GROUP 
    BY cat 
 ORDER 
    BY qty DESC 
 LIMIT 5
");

if($count_account = $result_account->num_rows) {
    while($row = $result_account->fetch_object()){
        $$key[$row->cat]= $row->qty;
    }
}

$result_previous = $db->query("SELECT nid, COUNT(cat) AS qty, dte, descript, cat, name, user FROM client_note AS cn JOIN client_note_tag_items AS cnti ON cnti.note_id = cn.nid JOIN client_note_tags AS cnt ON cnt.tag_id = cnti.tag_id WHERE (dte BETWEEN DATE_SUB(CURDATE(), INTERVAL 21 DAY) AND DATE_SUB(CURDATE(), INTERVAL 14 DAY)) AND name NOT LIKE 'Resolution%' GROUP BY cat ORDER BY qty DESC LIMIT 5");
if($count_previous = $result_previous->num_rows) {
    while($row_p = $result_previous->fetch_object()){
        $second_array[$row_p->cat]= $row_p->qty;
    }
}

foreach ($first_array as $key => $value) {
    $difference_array[$key]=$value - $second_array[$key];
}

foreach ($difference_array as $key => $value){
    echo "<tr>";
    echo "<td><h6>".$key."</h6></td><td><h3 class='text-primary'>".$value."</h3></td>";
    echo "</tr>";
}

我认为你在同一件事情上有太多的迭代。你可以将最后两个foreach循环合并成一个,并在输出结果之前进行差异比较。 - Cornel Raiu
1
是的,你说得对,我并没有尝试优化,只是给了一个提示。 - Tagarikdi Djakouba

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接