You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何单次查询获取单条记录?MySQL地址类型优先级查询需求

解决MySQL按优先级筛选peopleID对应记录的问题

嘿,这个需求我之前做项目的时候刚好遇到过,你说的没错,COALESCE确实搞不定——它只是用来取第一个非空的单个字段值,没法按优先级筛选整行记录;而单纯用CASE语句如果没搭配好逻辑,确实会出现重复记录。不过有两种靠谱的方法可以完美解决这个问题,分版本给你说说:

方法一:用窗口函数(MySQL 8.0+ 推荐)

窗口函数ROW_NUMBER()可以帮我们给每个peopleID下的记录按优先级排序,然后只取排名第一的那条,完全不会有重复。

思路:给每个peopleID分组,按照AddressTypeID的优先级(1 > 3)排序,然后筛选出每组排名为1的记录。

SELECT t.peopleID, t.AddressTypeID, t.其他字段名
FROM (
    SELECT 
        *,
        ROW_NUMBER() OVER (
            PARTITION BY peopleID 
            ORDER BY CASE AddressTypeID WHEN 1 THEN 1 WHEN 3 THEN 2 ELSE 3 END
        ) AS rn
    FROM 你的数据表名
    WHERE AddressTypeID IN (1, 3) -- 只关注我们需要的类型,提升查询效率
) t
WHERE t.rn = 1;

解释一下:

  • PARTITION BY peopleID:按peopleID分组,每组单独进行排序
  • ORDER BY CASE ...:给AddressTypeID=1的记录排第1位,=3的排第2位,其他类型排最后(如果表中有其他类型的话)
  • 外层筛选rn=1:只保留每组里优先级最高的那条记录

方法二:子查询+NOT EXISTS(兼容MySQL 5.x)

如果你的MySQL版本还没到8.0,没法用窗口函数,那就用这个方法:先取出所有AddressTypeID=1的记录,再补上那些没有1类型记录peopleID对应的3类型记录,这样组合起来就不会有重复。

-- 先取所有AddressTypeID=1的记录
SELECT peopleID, AddressTypeID, 其他字段名
FROM 你的数据表名
WHERE AddressTypeID = 1

UNION ALL

-- 再取那些没有1类型记录的peopleID的3类型记录
SELECT peopleID, AddressTypeID, 其他字段名
FROM 你的数据表名 t1
WHERE AddressTypeID = 3
AND NOT EXISTS (
    SELECT 1 
    FROM 你的数据表名 t2 
    WHERE t2.peopleID = t1.peopleID 
    AND t2.AddressTypeID = 1
);

解释一下:

  • UNION ALLUNION效率更高,因为不需要去重(这里两个查询的结果不会有重复的peopleID,所以放心用)
  • NOT EXISTS用来判断某个peopleID是否没有1类型的记录,只有满足这个条件才会取它的3类型记录

为什么COALESCE和单纯CASE不行?

  • COALESCE:它的作用是返回参数列表里第一个非NULL的值,比如COALESCE(字段1, 字段2),但你需要的是整行记录的优先级筛选,不是单个字段的非空判断,所以完全不适用。
  • 单纯CASE:如果只是写SELECT CASE WHEN AddressTypeID=1 THEN ... ELSE ... END,会把所有符合AddressTypeID=13的记录都列出来,同一个peopleID可能既有1又有3的记录,自然会重复;必须配合分组或筛选逻辑才能拿到唯一记录。

内容的提问来源于stack exchange,提问作者simplycoding

火山引擎 最新活动