【问题标题】:how to write the following SQL query involving sub queries如何编写以下涉及子查询的 SQL 查询
【发布时间】:2015-11-21 19:15:01
【问题描述】:

我有一个名为population的表格:

╔════════════╦════════════╦════════════════╗
║     india  ║ hyderabad  ║          50100 ║
║     india  ║ delhi      ║          75000 ║
║     USA    ║ NewYork    ║          25000 ║
║     USA    ║ california ║          30000 ║
║     india  ║  delhi     ║           5000 ║
║     USA    ║  NewYork   ║          75000 ║
╚════════════╩════════════╩════════════════╝

我需要编写一个 SQL 查询来获取以下格式的数据:

╔════════╦═════════╦══════════╗
║ india  ║ delhi   ║    80000 ║
║ USA    ║ NewYork ║   100000 ║
╚════════╩═════════╩══════════╝

国家名称和人口最多的城市,多个城市条目的总和。

【问题讨论】:

  • 加州不是城市
  • 另外,更严重的是,您没有 PRIMARY KEY,这可能会在适当的时候出现问题

标签: mysql sql


【解决方案1】:

你可以使用:

SELECT *
FROM (
  SELECT country,city, SUM(pop) AS total
  FROM population 
  GROUP BY country,city) AS sub
WHERE (country, total) IN (
                           SELECT country, MAX(total)
                           FROM (SELECT country,city, SUM(pop) AS total
                                 FROM population 
                                 GROUP BY country,city
                             ) as s
                           GROUP BY country
                           );

如果同一国家/地区的两个城市拥有相同的最高总人口,您将获得该国家/地区的两个城市。

SqlFiddleDemo

输出:

╔══════════╦═════════╦════════╗
║ country  ║  city   ║ total  ║
╠══════════╬═════════╬════════╣
║ india    ║ delhi   ║  80000 ║
║ USA      ║ NewYork ║ 100000 ║
╚══════════╩═════════╩════════╝

【讨论】:

    【解决方案2】:

    您可以结合使用 GROUP_CONCAT 和 FIND_IN_SET。此查询将返回以逗号分隔的每个国家/地区的城市列表,按人口 DESC 排序:

    SELECT country, GROUP_CONCAT(city ORDER BY pop DESC) AS cities
    FROM population
    GROUP BY country
    

    它会返回如下内容:

    | country |                   cities |
    |---------|--------------------------|
    |   india |    delhi,hyderabad,delhi |
    |     USA | NewYok,california,NewYok |
    

    然后我们可以使用返回城市列表中城市位置的 FIND_IN_SET 将该子查询连接回人口表:

    SELECT
      p.country,
      p.city,
      SUM(p.pop)
    FROM
      population p INNER JOIN (
        SELECT country, GROUP_CONCAT(city ORDER BY pop DESC) AS cities
        FROM population
        GROUP BY country
      ) m ON p.country=m.country
             AND FIND_IN_SET(p.city, m.cities)=1
    GROUP BY
      p.country,
      p.city
    

    只会在每个国家/地区人口最多的城市上成功加入:FIND_IN_SET(p.city, m.cities)=1

    只有当有一个城市的污染最高时,这才有效,如果有更多,只会返回一个。这也不是标准 SQL,仅适用于 MySQL 或类似数据库,其他 DBMS 具有窗口函数,可以使相同的查询更易于编写。

    【讨论】:

    • 对于多个城市,它不会返回多条记录。检查demoAND FIND_IN_SET(p.city, m.cities)=1 每个国家/地区只会得到一个
    • @lad2025 当然,对。我已经更新了我的答案。谢谢!
    • ? 有趣的方法
    【解决方案3】:

    以下答案不正确,因为它使用了违反 ANSI 标准的特定于 Mysql 的功能。结果不确定,因为未定义按国家/地区聚合时将返回哪个城市名称。大多数情况下,它是第一个将被使用的条目,这就是为什么内部查询中的排序在大多数情况下都可以工作。但请注意:根据定义,不能保证使用第一个城市,因此可能会出现输出错误结果的情况。 此答案未涵盖的另一种情况是,当有两个城市的人口与一个国家的最大人口相同时。此解决方案将只为每个国家/地区输出一个城市。

    我会用一个内部子查询来解决这个问题,它将所有城市分组,外部过滤器只得到国家/地区最大的。

    SELECT 
      country, city, MAX(population_total) AS population_total
    FROM 
      (
            SELECT country, city, SUM(population) AS population_total
            FROM tableName
            GROUP BY country, city
            ORDER BY population_total DESC
      ) AS t1
    GROUP BY 
      country
    

    【讨论】:

    • 城市将是不确定的
    • 返回任意城市
    • @Strawberry 你看到了吗,我在外部查询中使用了 SELECT MAX()?
    • stackoverflow.com/questions/33629168/… 并了解没有显式 agg 函数的分组
    • @JHoffmann 很高兴听到它。关键是与 SQL ANSI 标准相比,MySQL“滥用”了聚合。在子查询中使用显式order by,您可能会获得每组的第一条记录,但仍不能保证。另外,您的解决方案将无法处理同一国家的 2 个人口相同的城市(很少见,但可能)
    猜你喜欢
    • 1970-01-01
    • 2016-07-26
    • 1970-01-01
    • 2020-10-04
    • 2021-05-01
    • 2014-03-18
    • 2010-09-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多