【问题标题】:Get count of variable based on another variable根据另一个变量获取变量计数
【发布时间】:2015-05-15 12:19:12
【问题描述】:

我目前正在基于一些 json 数据构建一个 rapheal.js 地图,这些数据是我从 wordpress 中的数据库中导出的。我在构建 JSON 方面得到了一些帮助,但是我在处理一些需要计算的元素时遇到了麻烦。

如果您查看下面的脚本,您会注意到 gendercountry 两行。性别行可以是男性、女性或其他。国家显然是国家。我要做的是计算每个国家/地区的每个性别有多少,然后将其显示在工具提示数组 HTML 中。这意味着它需要首先检查国家/地区,然后检查每种性别中有多少人属于该国家/地区。

function mapInfo() {

  global $wpdb;

  $preJSON = array();

  // select only columns you need
  $sql = "SELECT * FROM wp_mas";


  //$count = 0; // this is for $preJSON[] index

  foreach( $wpdb->get_results( $sql ) as $key => $row ) {


      $value = $row->id;
      $latitude = $row->lat;
      $longitude = $row->long;
      $gender = $row->gender;
      $country = $row->country_srt;
      $tooltip = array(
          "content" => '<h2 class="country-name">- '. $country .' -</h2><p>female amount, male amount, other amount'
      );
      $main = array(
          "latitude" => $latitude,
          "longitude" => $longitude,
          "tooltip" => $tooltip
      );


      $preJSON[$country.$count] = array(
          "latitude" => $latitude,
          "longitude" => $longitude,
          "tooltip" => $tooltip
      );


      ++$count;
  }
  wp_send_json($preJSON);
}

我想我可以用一个 SQL 脚本来做到这一点,但我不想访问数据库两次。

【问题讨论】:

  • 我想我可以用 REPEAT 和几个子查询来解决这个问题,你能给我一份你的表格设计吗?
  • 你用$main做什么?你用$value做什么?
  • ps。不要评论$count = 0;。这将在 ++ 未初始化时向您发出警告。

标签: php mysql json wordpress


【解决方案1】:

首先,我认为在您使用的同一个循环中完成此任务是不可能的,因为它会弄乱循环的逻辑。基本上,您尝试处理所有结果行,而只处理一个(当前)行。所以我什至懒得去研究这种可能性。

相反,在 sql 中,只使用一个查询是非常可行的。我现在不知道数据库中到底有什么数据,但我认为它是这样的。

 id   lat    lng      gen  country   

  1     1       2      f    USA                  
  2     2       2      f    USA                  
  3     3       2      o    FRA                  
  5     4       3      m    FRA                  
  7     5       5      m    USA                  
  9     1       2      f    USA                  
 10     2       2      o    USA                  
 11     3       2      m    FRA                  
 12     4       3      f    FRA                  
 13     5       5      o    USA                  
 15     3       2      m    FRA                  
 16     4       3      f    FRA                  
 17     5       5      m    USA      

此查询将按原样获取表,并将与国家/地区匹配的每一行连续加入 fem、mal 和 oth 的总行数。

   SELECT 
    w.id as 'id', 
    w.lat as lat, 
    w.lng as lng, 
    w.gen as gen, 
    w.country as cntry, 
    c.count1 as cnt_fem, 
    c.count2 as cnt_mal, 
    c.count3 as cnt_oth
 FROM wp_mas as w
 LEFT OUTER JOIN
    (SELECT
        wp_mas.country as cntry1, 
        wp_mas.gen as gen1, 
        COUNT(case wp_mas.gen when 'Female' then 1 else NULL end) as count1, 
        COUNT(case wp_mas.gen when 'Male' then 1 else NULL end) as count2, 
        COUNT(case wp_mas.gen when 'Other' then 1 else NULL end) as count3
    FROM 
        wp_mas
    GROUP BY cntry1) 
 as c
 ON w.country=c.cntry1

也许,查询不是很优雅,但它有效。结果将是:

 id   lat    lng      gen     cntry     cnt_fem    cnt_mal    cnt_oth 

  1     1      2      f       USA             3          2          2 
  2     2      2      f       USA             3          2          2 
  3     3      2      o       FRA             2          3          1 
  5     4      3      m       FRA             2          3          1 
  7     5      5      m       USA             3          2          2 
  9     1      2      f       USA             3          2          2 
 10     2      2      o       USA             3          2          2 
 11     3      2      m       FRA             2          3          1 
 12     4      3      f       FRA             2          3          1 
 13     5      5      o       USA             3          2          2 
 15     3      2      m       FRA             2          3          1 
 16     4      3      f       FRA             2          3          1 
 17     5      5      m       USA             3          2          2 

每行将包含 3 列,其中女性、男性和其他人的总数与该行中的国家/地区相匹配。所以现在你可以使用你正在使用的相同循环:

  foreach( $wpdb->get_results( $sql ) as $key => $row ) {


      $value = $row->id;
      $latitude = $row->lat;
      $longitude = $row->lng;
      $gender = $row->gen;
      $country = $row->cntry;
      $cnt_fem = $row->cnt_fem;
      $cnt_mal = $row->cnt_mal;
      $cnt_oth = $row->cnt_oth;
      $tooltip = array(
          "content" => '<h2 class="country-name">- '. $country .' -</h2><p>'.$cnt_fem.' females, '.$cnt_mal.' males, '.$cnt_oth.' other'
      );


      $preJSON[$country.$count] = array(
          "latitude" => $latitude,
          "longitude" => $longitude,
          "tooltip" => $tooltip
      );


      ++$count;
  }
  wp_send_json($preJSON);
}

希望这会有所帮助。

【讨论】:

  • 我得到一个空数组。我的表如您所描述的那样,但是性别列有男性、女性和其他,而不是您所描述的 m、f、o。我相应地调整了 SQL,但它似乎没有输出任何东西。想知道我的经度是否存在负值问题。
  • 我刚刚注意到您的表名是“wp_mas”,但就我而言,我使用了“wp_maps”。我已经更新了 sql 查询。检查是否是问题所在。另外,我为列名使用了别名,因此数组的索引与您的索引略有不同。在你的 foreach 循环中仔细检查。
  • 我实际上已经在我的开发环境中更新了它。所以不确定是什么导致了这个问题。当我打印出该行时,我什么也得不到。如果您在以前的 cmets 中阅读过,我会因为负值而无法访问长表列,并且只有在我全选时才能访问它。想知道这是否是这里发生的问题。
  • 可能出现冲突是因为“long”也是一种数据类型,请尝试在查询中对其进行转义或将列名更改为其他名称,例如“lng”。
  • 这很有意义。我试试看
【解决方案2】:

使用 GROUP sql 你应该能够得到你要找的东西。

group by gender, country

这会将结果集更改为每个组的一个分组。

select count(*) as num_of_matches, gender, country, group_concat("id") as ids from wp_mas group by gender, country

会给你类似的东西

3, "male", "canada", "4,6,7"

如果 ids,您可以在“ids”上展开列表。

$ids = explode($row->ids, ",")

【讨论】:

  • 我希望不必使用另一个 SQL 命中并将其全部保存在 php 中。由于我选择了 ALL 和 count 我仍然可以访问我之前在原始 SQL 请求中所做的所有其他事情吗?
  • 处理来自相应分组的 SQL 数据库的结果集的一种折衷方案。也许像select * from wp_mas where id in (select group_concat("id") as ids from wp_mas group by gender, country)) 这样的东西。不确定这是否有效,但这个概念应该存在。
  • 我明白了。希望有一种方法可以通过 PHP 在原始语句中循环,并使用我已经返回的数据设置性别。我不太擅长使用更强大的 SQL 命令,也不知道如何将它们链接到我上面已经编写的代码中。
【解决方案3】:

我已修改您的代码以重用相同的 $sql 来获取每个国家/地区的不同性别数量。你应该试试这个,看看它是否有效。

$all_countries=array();
foreach( $wpdb->get_results( $sql ) as $key => $row ) {
    $value = $row->id;
    $latitude = $row->lat;
    $longitude = $row->long;
    $gender = $row->gender;
    $country = $row->country_srt;
    if(!isset($all_countries[$country][$gender])) $all_countries[$country][$gender] = array();
    array_push($all_countries[$country][$gender],array("value"=>$value,"latitude"=>$latitude,"longitude"=>$longitude));
}

$main=array();
foreach($all_countries as $country => $data){
    $tooltip = array("content" => '<h2 class="country-name">- '. $country .' -</h2><p>'.count($data['female']).', '.count($data['male']).', '.count($data['other']).'</p>');
    $gender='';
    if(count($data['male'])>0) $gender='male'; else if(count($data['female'])>0) $gender='female'; else $gender='other';
    array_push($main,array(
                                "latitude" => $data[$gender][0]['latitude'],
                                "longitude" => $data[$gender][0]['longitude'],
                                "tooltip" => $tooltip
                            ));
}
// Now you can do whatever you want with $main. echo its content as JSON or return, its upto you

$main 是您需要的最后一个数组。随心所欲。

【讨论】:

  • 呃……不。你的第二个 foreach 需要另一个 foreach 。你也没有设置 $latitude 等你是 array_pushing。所以所有推送的元素都将是第一个 foreach 的最后一个元素
  • 我在第二次 foreach 中犯了一个错误,我现在在我的回答中纠正了它。谢谢你@nl-x。
  • 这只会让我在最终数组中留下所有空值{ "value": null, "latitude": null, "longitude": null, "tooltip": { "content": "&lt;h2 class=\"country-name\"&gt;- USA -&lt;/h2&gt;&lt;p&gt;0, 0, 0&lt;/p&gt;" } },
  • @Mr.BigglesWorth 我上次编辑和测试代码是在 50 分钟前,也许您尝试了旧代码。请确认您尝试的代码是否相同。
  • 要检查的另一件事是,您在数据库中的性别是“男性”、“女性”还是“其他”。 0, 0, 0 的输出看起来很混乱。
【解决方案4】:

您需要做的就是将查询的结果遍历两次。不过,您不需要两次调用您的查询。只需先将结果引用到变量即可。

然后第一次 foreach 结果只是为了进行计数。然后再做你原来的 foreach,并在你的工具提示中使用计数值。

如下所示,我在一个单独的数组中进行了计数,该数组包含每个国家/性别组合的计数。

// select only columns you need
$sql = "SELECT * FROM wp_mas";
$result = $wpdb->get_results( $sql );
$count = 0;
foreach( $result as $row ) {
    if (!isset($count[$row->gender][$row->country_srt])) {
        $counters[$row->gender][$row->country_srt] = 0;
    }
    $counters[$row->gender][$row->country_srt] ++;
}
foreach( $result as $key => $row ) {
    $value = $row->id;
    $latitude = $row->lat;
    $longitude = $row->long;
    $gender = $row->gender;
    $country = $row->country_srt;
    $females = $counters['female'][$country];
    $males = $counters['male'][$country];
    $others = $counters['other'][$country];
    $tooltip = array(
        "content" => "<h2 class='country-name'>- $country -</h2><p>female $females, male $males, other $others"
    );
    $main = array(
        "latitude" => $latitude,
        "longitude" => $longitude,
        "tooltip" => $tooltip
    );
    $preJSON[$country . $count] = array(
        "latitude" => $latitude,
        "longitude" => $longitude,
        "tooltip" => $tooltip
    );
    ++$count;
}
wp_send_json($preJSON);

但是您可以通过保留未使用的变量并进行内联引用来压缩此代码:

$sql = "SELECT * FROM wp_mas"; // select only columns you need
$result = $wpdb->get_results( $sql );
$count = 0;
foreach( $result as $row )
    $counters[$row->gender][$row->country_srt] = isset($counters[$row->gender][$row->country_srt]) ? $counters[$row->gender][$row->country_srt] + 1 : 1;
foreach( $result as $key => $row )
    $preJSON[$row->country_srt . ++$count] = array(
        "latitude" => $row->lat,
        "longitude" => $row->long,
        "tooltip" => array(
            "content" => "<h2 class='country-name'>- {$row->country_srt} -</h2><p>female {$counters['female'][$row->country_srt]}, male {$counters['male'][$row->country_srt]}, other {$counters['other'][$row->country_srt]}"
        )
    );
wp_send_json($preJSON);

【讨论】:

  • 这让我对所有男性、女性和其他人都留有空白。我留下了"USA1": { "latitude": "41.94660000", "longitude": "-87.74660000", "tooltip": { "content": "&lt;h2 class='country-name'&gt;- USA -&lt;/h2&gt;&lt;p&gt;female , male , other " } }
  • 我在压缩代码中拼错了$row-&gt;country_srt。我现在修好了。你确定性别的拼写吗?它们不应该以大写字母开头吗?