我有大学选举的以下数据库计划:
对于每个部门,我有以下职位:
1 CHEF (这是candidate_position
= 1)
&安培; 6位成员(candidate_position
= 2)
我想获得各部门选举的获胜者。
为获得“Informatique”部门的CHEF职位获胜者,我做了以下查询:
SELECT doctor.firstname, doctor.lastname, votes
FROM (SELECT COUNT(*) AS votes FROM candidate_votes WHERE candidate_votes.candidate_position = 1 GROUP BY candidate_votes.candidate_id) AS votes, doctor
INNER JOIN department_candidates ON department_candidates.doctor_id = doctor.id
INNER JOIN department ON department.id = department_candidates.department_id AND department.name = 'Informatique'
INNER JOIN candidate_votes ON candidate_votes.candidate_id = doctor.id AND candidate_votes.candidate_position = 1
GROUP BY candidates_votes.candidate_id
请注意我没有使用LIMIT 1
,因为可能在多个候选人之间有一个平局(或平局)
根据结果,我认为我选择Chef
位置获胜者的查询是正确的,但我想知道如何选择Member
位置的前6位候选人? / p>
数据集:
--
-- Table structure for table `candidate_votes`
--
DROP TABLE IF EXISTS `candidate_votes`;
CREATE TABLE IF NOT EXISTS `candidate_votes` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`candidate_id` int(11) NOT NULL,
`voter_id` int(11) NOT NULL,
`candidate_position` tinyint(1) NOT NULL COMMENT '1: chef, 2: member',
`date` date NOT NULL,
PRIMARY KEY (`id`),
KEY `fk-candidate_votes-voter_id` (`voter_id`),
KEY `fk-candidate_votes-candidate_id_idx` (`candidate_id`)
) ENGINE=InnoDB AUTO_INCREMENT=36 DEFAULT CHARSET=utf8;
--
-- Dumping data for table `candidate_votes`
--
INSERT INTO `candidate_votes` (`id`, `candidate_id`, `voter_id`, `candidate_position`, `date`) VALUES
(24, 2, 1, 1, '2018-05-26'),
(25, 1, 1, 2, '2018-05-26'),
(26, 6, 1, 2, '2018-05-26'),
(27, 5, 1, 2, '2018-05-26'),
(28, 7, 1, 2, '2018-05-26'),
(29, 8, 1, 2, '2018-05-26'),
(30, 9, 1, 2, '2018-05-26'),
(31, 2, 2, 1, '2018-05-16'),
(32, 3, 7, 1, '2018-05-22'),
(33, 3, 8, 1, '2018-05-22'),
(34, 4, 6, 2, '2018-05-29'),
(35, 7, 6, 2, '2018-05-29');
-- --------------------------------------------------------
--
-- Table structure for table `department`
--
DROP TABLE IF EXISTS `department`;
CREATE TABLE IF NOT EXISTS `department` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `department-name` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
--
-- Dumping data for table `department`
--
INSERT INTO `department` (`id`, `name`) VALUES
(1, 'Informatique'),
(2, 'Mathematique'),
(4, 'physique');
-- --------------------------------------------------------
--
-- Table structure for table `department_candidates`
--
DROP TABLE IF EXISTS `department_candidates`;
CREATE TABLE IF NOT EXISTS `department_candidates` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`department_id` int(11) NOT NULL,
`doctor_id` int(11) NOT NULL,
`candidate_position` tinyint(1) NOT NULL COMMENT '1: chef, 2: member',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=15 DEFAULT CHARSET=utf8;
--
-- Dumping data for table `department_candidates`
--
INSERT INTO `department_candidates` (`id`, `department_id`, `doctor_id`, `candidate_position`) VALUES
(5, 1, 3, 1),
(7, 1, 4, 2),
(8, 1, 1, 2),
(9, 1, 2, 1),
(10, 1, 6, 2),
(11, 1, 5, 2),
(12, 1, 7, 2),
(13, 1, 8, 2),
(14, 1, 9, 2);
-- --------------------------------------------------------
--
-- Table structure for table `doctor`
--
DROP TABLE IF EXISTS `doctor`;
CREATE TABLE IF NOT EXISTS `doctor` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`firstname` varchar(255) NOT NULL,
`lastname` varchar(255) NOT NULL,
`department_id` int(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8;
--
-- Dumping data for table `doctor`
--
INSERT INTO `doctor` (`id`, `firstname`, `lastname`, `department_id`) VALUES
(1, 'doc1_fn', 'doc1_ln', 1),
(2, 'doc2_fn', 'doc2_ln', 1),
(3, 'doc3_fn', 'doc3_ln', 1),
(4, 'doc4_fn', 'doc4_ln', 1),
(5, 'doc5_fn', 'doc5_ln', 1),
(6, 'doc6_fn', 'doc6_ln', 1),
(7, 'doc7_fn', 'doc7_ln', 1),
(8, 'doc8_fn', 'doc8_ln', 1),
(9, 'doc9_fn', 'doc9_ln', 1);
-- --------------------------------------------------------
答案 0 :(得分:1)
请考虑以下事项:
SELECT x.*
, CASE WHEN @prev_position = candidate_position THEN CASE WHEN @prev_total = total THEN @i:=@i ELSE @i:=@i+1 END ELSE @i:=1 END i
, @prev_position := candidate_position prev_position
, @prev_total := total prev_total
FROM
(
SELECT candidate_id
, candidate_position
, COUNT(*) total
FROM candidate_votes
GROUP
BY candidate_id
, candidate_position
) x
JOIN
( SELECT @prev_position := null,@prev_total:=null,@i:=0) vars
ORDER
BY candidate_position
, total DESC;
+--------------+--------------------+-------+------+---------------+------------+
| candidate_id | candidate_position | total | i | prev_position | prev_total |
+--------------+--------------------+-------+------+---------------+------------+
| 2 | 1 | 2 | 1 | 1 | 2 |
| 3 | 1 | 2 | 1 | 1 | 2 |
| 7 | 2 | 2 | 1 | 2 | 2 |
| 8 | 2 | 1 | 2 | 2 | 1 |
| 9 | 2 | 1 | 2 | 2 | 1 |
| 1 | 2 | 1 | 2 | 2 | 1 |
| 4 | 2 | 1 | 2 | 2 | 1 |
| 5 | 2 | 1 | 2 | 2 | 1 |
| 6 | 2 | 1 | 2 | 2 | 1 |
+--------------+--------------------+-------+------+---------------+------------+
在此示例中,i
表示排名。对于位置1,我们可以看到两名候选人并列第一名。对于位置2,有一个直接赢家,剩下的所有候选人都争夺第二名。
答案 1 :(得分:1)
显然我试图在我的其他答案中太聪明,你可以实现这样一个简单的排名表:
SELECT cast(dc.candidate_position AS UNSIGNED) AS position, dc.doctor_id, doc.firstname, doc.lastname, v.votes
FROM department_candidates dc
JOIN department dept ON dept.id=dc.department_id AND dept.name='Informatique'
JOIN doctor doc ON doc.id=dc.doctor_id
JOIN (SELECT candidate_position AS cp, candidate_id AS cid, count(candidate_id) AS votes
FROM candidate_votes
GROUP BY cid) v
ON v.cid=doc.id AND v.cp = dc.candidate_position
ORDER BY position, v.votes DESC
输出:
position doctor_id firstname lastname votes
1 3 doc3_fn doc3_ln 2
1 2 doc2_fn doc2_ln 2
2 7 doc7_fn doc7_ln 2
2 4 doc4_fn doc4_ln 1
2 1 doc1_fn doc1_ln 1
2 6 doc6_fn doc6_ln 1
2 5 doc5_fn doc5_ln 1
2 8 doc8_fn doc8_ln 1
2 9 doc9_fn doc9_ln 1
答案 2 :(得分:0)
此查询将为您提供获得某个位置所需的投票数(请注意我已将其与变量进行参数化):
SET @position = 2;
SET @numwinners = 3;
SELECT @rank := @rank+1 AS rank, votes
FROM (SELECT COUNT(candidate_id) AS votes
FROM candidate_votes
WHERE candidate_position = @position
GROUP BY candidate_id
ORDER BY votes DESC) vr
JOIN (select @rank := 0) r
GROUP BY rank
HAVING rank = @numwinners
使用@position=2
和@numwinners=3
输出您的数据:
rank votes
3 1
在确定需要多少票之后,我们只需要找到所有具有所需票数的候选人。由于结果基于投票数,因此会自动处理关系。此查询将生成该输出:
SET @position = 2;
SET @numwinners = 3;
SELECT doc.firstname, doc.lastname, v.votes
FROM department_candidates dc
JOIN department dept ON dept.id=dc.department_id AND dept.name='Informatique'
JOIN doctor doc ON doc.id=dc.doctor_id
JOIN (SELECT candidate_id AS cid, count(candidate_id) AS votes
FROM candidate_votes
WHERE candidate_position = @position
GROUP BY cid) v
ON v.cid=dc.id
WHERE v.votes >= (SELECT votes
FROM (SELECT @rank := @rank+1 AS rank, votes
FROM (SELECT COUNT(candidate_id) AS votes
FROM candidate_votes
WHERE candidate_position = @position
GROUP BY candidate_id
ORDER BY votes DESC) vr
JOIN (select @rank := 0) r
GROUP BY rank
HAVING rank = @numwinners
) vt
)
ORDER BY v.votes DESC
使用@position=2
和@numwinners=3
输出您的数据:
firstname lastname votes
doc7_fn doc7_ln 2
doc4_fn doc4_ln 1
doc1_fn doc1_ln 1
doc6_fn doc6_ln 1
doc5_fn doc5_ln 1
doc8_fn doc8_ln 1
doc9_fn doc9_ln 1
使用@position=1
和@numwinners=1
输出您的数据:
firstname lastname votes
doc3_fn doc3_ln 2
doc2_fn doc2_ln 2
如果您想确保查询有效,即使@numwinners
的值大于候选人数,请更改:
HAVING rank = @numwinners
到
HAVING rank = LEAST(@numwinners, (SELECT COUNT(DISTINCT candidate_id)
FROM candidate_votes
WHERE candidate_position = @position))