You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

寻求更优雅的MySQL查询优化方案:消除WHERE语句重复问题

优化MySQL查询:避免重复WHERE条件的优雅解法

需求回顾

找出拥有至少10个得票超过100的席位(seggio)的列表(lista),并展示对应的席位信息。

表结构

CREATE TABLE `scrutini_l` (
    `lista` char(20) NOT NULL,
    `seggio` int(11) NOT NULL,
    `territorio` int(11) NOT NULL,
    `voti` int(11) NOT NULL,
    PRIMARY KEY (`lista`, `seggio`, `territorio`),
    KEY `scrutini_l_ibfk_2` (`seggio`),
    KEY `scrutini_l_ibfk_3` (`territorio`),
    CONSTRAINT `scrutini_l_ibfk_1` FOREIGN KEY (`lista`) REFERENCES `liste` (`nome`) ON DELETE CASCADE ON UPDATE CASCADE,
    CONSTRAINT `scrutini_l_ibfk_2` FOREIGN KEY (`seggio`) REFERENCES `seggi` (`numero`) ON DELETE CASCADE ON UPDATE CASCADE,
    CONSTRAINT `scrutini_l_ibfk_3` FOREIGN KEY (`territorio`) REFERENCES `seggi` (`territorio`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4

现有问题

你当前的查询重复使用了WHERE voti > 100条件,显得冗余:

select lista, seggio, territorio
from scrutini_l
where voti > 100
and lista in
    (select lista
     from scrutini_l
     where voti > 100
     group by lista
     having count (*) >= 10);

优雅解决方案

方案1:使用窗口函数(MySQL 8.0+ 推荐)

窗口函数可以一次性完成过滤和分组统计,全程只需写一次voti > 100,逻辑连贯且可读性强:

SELECT lista, seggio, territorio
FROM (
    SELECT 
        lista, seggio, territorio,
        -- 按lista分组,统计当前组内符合过滤条件的记录数
        COUNT(*) OVER (PARTITION BY lista) AS valid_seat_count
    FROM scrutini_l
    WHERE voti > 100
) AS filtered_results
-- 筛选出符合席位数量要求的列表
WHERE valid_seat_count >= 10;

方案2:使用CTE(公共表表达式,MySQL 8.0+)

通过CTE复用过滤后的数据集,避免重复写过滤条件,代码结构更清晰:

-- 先定义所有得票超过100的席位记录
WITH valid_seats AS (
    SELECT lista, seggio, territorio
    FROM scrutini_l
    WHERE voti > 100
)
-- 从过滤后的记录中,筛选出符合席位数量要求的列表
SELECT vs.lista, vs.seggio, vs.territorio
FROM valid_seats vs
JOIN (
    SELECT lista
    FROM valid_seats
    GROUP BY lista
    HAVING COUNT(*) >= 10
) AS qualified_lists ON vs.lista = qualified_lists.lista;

方案3:兼容低版本MySQL(<8.0)

如果你的MySQL版本不支持窗口函数和CTE,可以用JOIN替代IN子查询,虽然仍需写两次过滤条件,但执行计划通常比IN子查询更高效,结构也更清晰:

SELECT s.lista, s.seggio, s.territorio
FROM scrutini_l s
-- 关联符合条件的列表数据集
JOIN (
    SELECT lista
    FROM scrutini_l
    WHERE voti > 100
    GROUP BY lista
    HAVING COUNT(*) >= 10
) AS qualified ON s.lista = qualified.lista
WHERE s.voti > 100;

方案对比

  • 窗口函数/CTE方案:代码最简洁,无重复条件,逻辑一目了然,适合MySQL 8.0及以上版本。
  • JOIN方案:兼容低版本MySQL,性能优于原IN子查询方案,结构比原查询更清晰。

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 23:05:18