计算范围百分比

Calculate percentages on ranges

我有以下 table 数据:

+----------+------------+-----------+
| country  | age        | gender    |
+----------+------------+-----------+
| China    |    15      |  male     |
+----------+------------+-----------+
| China    |     25     |   female  |
+----------+------------+-----------+
| China    |     50     |  male     |
+----------+------------+-----------+
| China    |     62     | male      |
+----------+------------+-----------+
| Burma    |     25     |   female  |
+----------+------------+-----------+
| Burma    |     50     |  male     |
+----------+------------+-----------+
| France   |    27      | male      |
+----------+------------+-----------+
| France   |    55      | female    |
+----------+------------+--------- -+

我想查询 select,结果如下:

+----------+-----------+---------+-----------+-----------------+----------------+
| region   | age_range |  gender | count     | gender_percent  | total_percent  |
+----------+-----------+---------+-----------+-----------------+----------------+
| Asia     |  0-49     | male    |   1       |     33          |   12.5         |
+----------+---------- +---------+-----------+-----------------+----------------+
| Asia     |  0-49     | female  |   2       |     67          |   25           |
+----------+-----------+---------+-----------+--------------- -+----------------+
| Asia     |  50+      | male    |   3       |   100           |   37.5         |
+----------+-----------+---------+-----------+-----------------+----------------+
| Europe   | 0-49      | male    |   1       |    100          |  12.5          |
+----------+-----------+---------+-----------+-----------------+----------------+
| Europe   | 50+       | female  |   1       |    100          |  12.5          |
+----------+-----------+------- -+-----------+-----------------+----------------+

即。我想计算数据范围的不同百分比。每个国家(地区)和年龄段的性别各占一个百分比,占总数各占一个百分比。

我该怎么做?

我更喜欢交叉 RDBMS 解决方案,它尽可能减少硬编码。速度和简单性也是主要方面。我正在 MySQL 上开发,但该解决方案稍后将移植到 Oracle 和 MS SQL。

非常感谢。

我把地区作为国家的一列。在 select 中,我使用 CASE 来获取范围标签。如果不想添加 region 字段

,您可以对 region 执行相同的操作
CREATE TABLE country
    (`region` varchar(6), `country` varchar(6), `age` int, `gender` varchar(6))
;

INSERT INTO country
    (`region`, `country`, `age`, `gender`)
VALUES
    ('Asia', 'China', 15, 'male'),
    ('Asia', 'China', 25, 'female'),
    ('Asia', 'China', 50, 'male'),
    ('Asia', 'China', 62, 'male'),
    ('Asia', 'Burma', 25, 'female'),
    ('Asia', 'Burma', 50, 'male'),
    ('Europe', 'France', 27, 'male'),
    ('Europe', 'France', 55, 'female')
;

SqlFiddleDemo

SELECT region.*, 
       (count_range_gender / region_range_total.gender_total) * 100 as gender_percent,
       (count_range_gender / world.world_total) * 100 as total_percent
FROM 
    (
      SELECT `region`,
             CASE WHEN age < 50 then '0-49' 
                  ELSE '50+'
             END age_range,
             gender, 
             count(country) as count_range_gender
      FROM country
      GROUP BY `region`,
               CASE WHEN age < 50 then '0-49' 
                    ELSE '50+'
               END,
               gender
      ) region
JOIN 
    (
      SELECT `region`,  
              CASE WHEN age < 50 then '0-49' 
                  ELSE '50+'
              END age_range, 
              count(country) as gender_total
      FROM country   
      GROUP BY `region`,
               CASE WHEN age < 50 then '0-49' 
                    ELSE '50+'
               END
     ) region_range_total
  ON region.region = region_range_total.region
 AND region.age_range = region_range_total.age_range
CROSS JOIN 
    (
      SELECT count(country) as world_total
      FROM country         
     ) world

输出

| region | age_range | gender | count_range_gender | gender_percent | total_percent |
|--------|-----------|--------|--------------------|----------------|---------------|
|   Asia |      0-49 | female |                  2 |        66.6667 |            25 |
|   Asia |      0-49 |   male |                  1 |        33.3333 |          12.5 |
|   Asia |       50+ |   male |                  3 |            100 |          37.5 |
| Europe |      0-49 |   male |                  1 |            100 |          12.5 |
| Europe |       50+ | female |                  1 |            100 |          12.5 |

编辑

在MySql中你也可以使用IF(age < 50, '0-49', '50+')

这里是完整的答案。无论如何,如果没有@Juan Carlos Oropeza 的回答,我将无法做到。再次感谢胡安 :-)

SELECT region.*, 
   (`count` / region_range_total.gender_total) * 100 as gender_percent,
   (`count` / (select count(*) from country)) * 100 as total_percent
  FROM 
   (
    SELECT
      CASE country 
        WHEN 'China' then 'Asia'
        WHEN 'Burma' then 'Asia'
        WHEN 'France' then 'Europe'
      END region,
      CASE WHEN age < 50 then '0-49' 
         ELSE '50+'
      END age_range,
      gender, 
      count(country) as `count`
  FROM country
  GROUP BY 
      region,  
      age_range,
      gender
  ) region
JOIN 
  (
  SELECT 
      CASE country 
        WHEN 'China' then 'Asia'
        WHEN 'Burma' then 'Asia'
        WHEN 'France' then 'Europe'
      END region,  
      CASE WHEN age < 50 then '0-49' 
          ELSE '50+'
      END age_range, 
      count(country) as gender_total
  FROM country   
  GROUP BY 
      region, 
      age_range
 ) region_range_total
 ON region.region = region_range_total.region
 AND region.age_range = region_range_total.age_range