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

基于四张关联MySQL表按区域统计候选人得票数的SQL查询问题

需求:实现投票数据的交叉表统计

现有四张关联MySQL表,表结构如下:

表 tblvotes

字段(Field)类型(Type)是否为空(Null)键(Key)默认值(Default)额外属性(Extra)
idint(11)NOPRINULLauto_increment
candidateidint(11)NOMULNULL
districtidint(11)NONULL
daterecordeddatetimeNOcurrent_timestamp()

表 tblcandidate

字段(Field)类型(Type)是否为空(Null)键(Key)默认值(Default)额外属性(Extra)
idint(11)NOPRINULLauto_increment
voteridint(11)NOMULNULL
partyidint(11)NOMULNULL
candidatepositionidint(11)NOMULNULL

表 tbldistricts

字段(Field)类型(Type)是否为空(Null)键(Key)默认值(Default)额外属性(Extra)
idint(11)NOPRINULLauto_increment
district_shortvarchar(8)NONULL
district_namevarchar(100)NONULL
district_aunvarchar(10)NONULL
district_propValtinyint(4)NO1

表 tblvoterlist

字段(Field)类型(Type)是否为空(Null)键(Key)默认值(Default)额外属性(Extra)
idint(11)NOPRINULLauto_increment
idnovarchar(15)YESNULL
lastnamevarchar(30)NONULL
firstnamevarchar(30)NONULL
middlenamevarchar(30)NONULL
districtidint(5)YESMULNULL
imagevarchar(30)NONULL
votingcodevarchar(15)YESUNINULL
votestatuschar(1)YESNULL
yearlevelidint(12)YESMULNULL

我尝试编写了如下SQL语句:

SELECT concat_ws(",", tvl.lastname, tvl.firstname) as candidate, td.district_name as district,  count(tv.candidateid) 
FROM tblvotes tv
JOIN tblcandidate tc on tv.candidateid = tc.id
JOIN tbldistricts td on tv.districtid = td.id
JOIN tblvoterlist tvl on tc.voterid = tvl.id

我也尝试按tv.districtid分组,但不确定COUNT函数的正确使用位置,也不理解如何利用表的关联键实现期望的结果。我期望得到的结果是交叉表形式,示例如下:

Candidate1Candidate2Candidate3Candidate4
District15210
District20421
District36232

请求帮助编写正确的SQL语句实现该需求。


解决方案

要实现这种交叉表(行转列)的统计,需要用到MySQL的条件聚合结合分组,具体SQL语句如下:

SELECT 
    td.district_name AS ``,
    COUNT(CASE WHEN concat_ws(',', tvl.lastname, tvl.firstname) = 'Candidate1' THEN tv.id END) AS `Candidate1`,
    COUNT(CASE WHEN concat_ws(',', tvl.lastname, tvl.firstname) = 'Candidate2' THEN tv.id END) AS `Candidate2`,
    COUNT(CASE WHEN concat_ws(',', tvl.lastname, tvl.firstname) = 'Candidate3' THEN tv.id END) AS `Candidate3`,
    COUNT(CASE WHEN concat_ws(',', tvl.lastname, tvl.firstname) = 'Candidate4' THEN tv.id END) AS `Candidate4`
FROM tbldistricts td
LEFT JOIN tblvotes tv ON td.id = tv.districtid
LEFT JOIN tblcandidate tc ON tv.candidateid = tc.id
LEFT JOIN tblvoterlist tvl ON tc.voterid = tvl.id
GROUP BY td.id, td.district_name
ORDER BY td.district_name;

关键说明:

  1. LEFT JOIN的使用:确保即使某个选区没有给特定候选人投票,也能显示0而不是过滤掉该行。
  2. 条件聚合:通过CASE WHEN判断当前行属于哪个候选人,用COUNT统计有效记录(非NULL的情况),没有匹配的会返回NULL,COUNT会忽略NULL,从而得到0的结果。
  3. 分组规则:按选区的ID和名称分组,确保每个选区只返回一行统计结果。
  4. 候选人名称替换:需要把语句中的'Candidate1'等替换为实际的候选人姓名(格式为姓氏,名字,和concat_ws的结果一致)。

如果候选人是动态的(数量不固定),MySQL无法直接通过静态SQL实现,这种情况下需要用存储过程拼接动态SQL来生成对应列。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 12:51:56