SQLite GROUP BY多列求和:如何批量聚合政党得票列?
哈哈,太懂这种列多到让人崩溃的感觉了!手动写几十个SUM(party_xxx)完全是浪费时间,下面给你分不同主流数据库讲最实用的解决办法:
分数据库解决方案
1. MySQL/MariaDB
MySQL里可以用动态SQL自动生成所有政党列的求和语句,不用手动列出来:
-- 第一步:生成所有政党列的SUM拼接字符串 SET @sql = NULL; SELECT GROUP_CONCAT(DISTINCT CONCAT('SUM(', column_name, ') AS ', column_name)) INTO @sql FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = '你的数据库名称' -- 替换成你的库名 AND table_name = 'results' AND column_name NOT IN ('town_code', 'ballot_code'); -- 第二步:拼接完整的GROUP BY查询语句 SET @sql = CONCAT('SELECT town_code, ballot_code, ', @sql, ' FROM results GROUP BY town_code, ballot_code'); -- 第三步:执行生成的SQL PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
原理是通过INFORMATION_SCHEMA.COLUMNS获取表中所有非分组列(也就是政党列),用GROUP_CONCAT把它们拼接成SUM(partyA) AS partyA, SUM(partyB) AS partyB...的格式,再拼到主查询里执行。
2. PostgreSQL
PostgreSQL的思路类似,用动态SQL+系统视图来生成语句,还能自动处理特殊列名:
DO $$ DECLARE cols text; BEGIN -- 获取所有政党列的SUM拼接字符串 SELECT string_agg(DISTINCT 'SUM(' || quote_ident(column_name) || ') AS ' || quote_ident(column_name), ', ') INTO cols FROM information_schema.columns WHERE table_schema = 'public' -- 替换成你的schema,默认是public AND table_name = 'results' AND column_name NOT IN ('town_code', 'ballot_code'); -- 执行拼接好的查询 EXECUTE format('SELECT town_code, ballot_code, %s FROM results GROUP BY town_code, ballot_code', cols); END $$;
quote_ident会自动给有特殊字符的列名加引号,避免语法错误;format函数让SQL拼接更安全。
3. SQL Server
SQL Server用sys.columns系统视图获取列名,结合动态SQL实现:
DECLARE @cols NVARCHAR(MAX); DECLARE @sql NVARCHAR(MAX); -- 生成政党列的SUM拼接字符串(SQL Server 2017+支持STRING_AGG) SELECT @cols = STRING_AGG(CONCAT('SUM(', QUOTENAME(name), ') AS ', QUOTENAME(name)), ', ') FROM sys.columns WHERE object_id = OBJECT_ID('results') AND name NOT IN ('town_code', 'ballot_code'); -- 拼接并执行查询 SET @sql = CONCAT('SELECT town_code, ballot_code, ', @cols, ' FROM results GROUP BY town_code, ballot_code'); EXEC sp_executesql @sql;
如果是SQL Server 2016及更早版本,把STRING_AGG换成FOR XML PATH的写法即可:
SELECT @cols = STUFF((SELECT ', SUM(' + QUOTENAME(name) + ') AS ' + QUOTENAME(name) FROM sys.columns WHERE object_id = OBJECT_ID('results') AND name NOT IN ('town_code', 'ballot_code') FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 1, '');
补充说明
为什么不能直接用关键字批量指代这些列?因为SQL标准里没有“所有非分组列自动聚合”的语法(SELECT *在GROUP BY后不允许,除非数据库有非标准扩展,但也不能自动加SUM),所以动态SQL是目前最通用的解决方案。
而且这个方法的好处是:以后新增政党列,不用修改查询语句,动态SQL会自动包含新列的求和。
内容的提问来源于stack exchange,提问作者localhost
相关产品推荐
相关产品推荐

