社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  DATABASE

mysql-返回不同记录的条件最小最大值

adam78 • 5 年前 • 1708 次点击  

我有一个数据库转储 the geonames website for Great Britain . 它包含大约60000条记录。 示例数据如下:

id       |     name    |   admin1   |   admin2   |  admin3  |  feature_class  |  feature_code
-------------------------------------------------------------------------------------------
2652355  |   Cornwall  |   ENG      |     C6     |          |      A          |    ADM2
11609029 |   Cornwall  |   ENG      |            |          |      L          |    RGN
6269131  |   England   |   ENG      |            |          |      A          |    ADM1

功能代码为ADM2的第一条记录表示它是管理级别2 具有特征码RGN的分段记录意味着它是一个区域。

我想按地名搜索记录以建立自动完成功能。 如果记录具有相同的名称,如果其中一个记录是一个区域,即具有特征代码RGN,那么我只想返回 否则,我想返回与具有最低id的名称匹配的记录。

我试过以下方法,但不起作用:

   SELECT IF(t0.feature_code = 'RGN', MAX(t0.id), MIN(t0.id)) as id
       , CONCAT_WS(', ', t0.name,
                  IF(t3.name != t0.name, t3.name, NULL),
                  IF(t2.name != t0.name, t2.name, NULL),
                  IF(t1.name != t0.name, t1.name, NULL)) AS name
     FROM locations t0
  LEFT JOIN locations t1 ON t1.admin1 = t0.admin1 AND t1.feature_code = 'ADM1'
  LEFT JOIN locations t2 ON t2.admin2 = t0.admin2 AND t2.feature_code = 'ADM2'
  LEFT JOIN locations t3 ON t3.admin3 = t0.admin3 AND t3.feature_code = 'ADM3'
  WHERE 
      (t0.feature_class IN ('P', 'A') OR (t0.feature_class = 'L' AND t0.feature_code = 'RGN' ) )
      AND t0.name like 'Cornwall%' 
  GROUP BY CONCAT_WS(', ', t0.name,
                     IF(t3.name != t0.name, t3.name, NULL),
                     IF(t2.name != t0.name, t2.name, NULL),
                     IF(t1.name != t0.name, t1.name, NULL))
  ORDER BY t0.name 

它返回错误的记录:

id      | name
---------------------------
2652355 | Cornwall, England
Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/43423
 
1708 次点击  
文章 [ 3 ]  |  最新文章 5 年前
Zaynul Abadin Tuhin
Reply   •   1 楼
Zaynul Abadin Tuhin    6 年前

一种方法可以存在并联合所有

select t1.* from location t1
where exists ( select 1 from location t2 where t2.name=t1.name and t2.feature_code='RGN'
             )
 and t1.feature_code='RGN'
union all

select t1.* from location t1
where not exists ( select 1 from location t2 where t2.name=t1.name and 
                t2.feature_code='RGN'
                  )
  and t1.id=(select min(id) from location t2 where t2.name=t1.name)
Gordon Linoff
Reply   •   2 楼
Gordon Linoff    6 年前

在MySQL中,可以使用相关的子查询:

select l.*
from locations l
where l.id = (select l2.id
              from locations l2
              where l2.name = l.name
              order by (feature_code = 'RGN') desc,  -- put regions first
                       id asc
             );

在MySQL 8 +中,也可以使用 row_number() :

select l.*
from (select l.*,
             row_number() over (partition by name 
                                order by (feature_code = 'RGN') desc, id
                               ) as seqnum
      from locations l
     ) l
where seqnum = 1;
GMB
Reply   •   3 楼
GMB    6 年前

我认为 条件聚合 应该会成功的。可以通过以下方式过滤记录 name ,然后在聚合函数中应用逻辑。如果记录存在于 feature_code = 'RGN' 然后选择它,否则选择最小值 id 在匹配记录中。

SELECT IFNULL(MAX(CASE WHEN feature_code = 'RGN' THEN id END), MIN(id)) id_found
FROM mytable
WHERE name = @name;

Demo on DB Fiddle 搜索时 'Cornwall' :

| id_found |
| -------- |
| 11609029 |

注意:如果您想要整个匹配记录,一个解决方案是 JOIN 以上结果与原表一致:

SELECT t.*
FROM mytable t
INNER JOIN (
    SELECT IFNULL(MAX(CASE WHEN feature_code = 'RGN' THEN id END), MIN(id)) id_found
    FROM mytable
    WHERE name = @name
) x ON x.id_found = t.id;

Demo :

| id       | name     | admin1 | admin2 | admin3 | feature_class | feature_code |
| -------- | -------- | ------ | ------ | ------ | ------------- | ------------ |
| 11609029 | Cornwall | ENG    |        |        | L             | RGN          |