我有两张表StudentTable
和LevelsTable
。我使用的是Java和Sqlite。
我的第一张桌子:StudentTable
+----+-----------+-------------+-----------+---------------+
| idS| firstName | famillyName | age | pushUps |
+----+-----------+-------------+-----------+---------------+
| 1 | a | d | 17 | 20 |
| 2 | b | e | 18 | 30 |
| 3 | c | f | 19 | 50 |
+----+-----------+-------------+-----------+---------------+
我的第二张桌子:LevelsTable
+----+-----------+--------+-----------+--------+--------------+
| idP| veryWeak | weak | average | good | veryGood |
+----+-----------+--------+-----------+--------+--------------+
| 1 | 10 | 15 | 20 | 30 | 40 |
+----+-----------+--------+-----------+--------+--------------+
我想计算每个级别的学生人数,具体取决于每个级别的俯卧撑数量。 例如:如果我有1000名学生,我想得到这样的结果:
您对解决方案有何建议?
答案 0 :(得分:1)
使用纯SQL,你可以这样做:
O(n * T * R)
<强>更新强>
正如我在评论中提到的,您的SELECT CASE x.studentLevel WHEN 0 THEN 'super-duper weak'
WHEN 1 THEN 'very weak'
WHEN 2 THEN 'weak'
WHEN 3 THEN 'average'
WHEN 4 THEN 'good'
WHEN 5 THEN 'very good'
END AS "level"
, COUNT(*) AS "count"
FROM ( SELECT CASE WHEN s.pushUps >= lvl.veryGood THEN 5
WHEN s.pushUps >= lvl.good THEN 4
WHEN s.pushUps >= lvl.average THEN 3
WHEN s.pushUps >= lvl.weak THEN 2
WHEN s.pushUps >= lvl.veryWeak THEN 1
ELSE 0
END AS studentLevel
FROM StudentTable s
, LevelsTable lvl
WHERE lvl.idP = 1/*pushUps*/
) x
GROUP BY x.studentLevel
ORDER BY x.studentLevel
对SQL来说不是很方便。 Strawberry 在另一个答案中建议的表是朝着正确方向迈出的一步,但需要两个变化:它需要多组水平,水平应该是范围,上下边界。
对于多组范围,您需要一个标识该组的列。我们称之为LevelsTable
,并保持简单易用,让它成为命名该类型的文本列,例如levelType
。
对于范围边界,一种方式是低位和高位,例如'pushUps'
,0-9
,依此类推。如果你的值可以是浮点数,那将不会起作用,因为10-19
将介于范围之间,所以最好使边界包含更低且更高的范围,就像你在问题
如果需要,您可以保留9.5
列,但不需要。
idP
现在,如果你想列出学生并展示他们的水平,那很简单:
CREATE TABLE LevelsTable (
levelType VARCHAR(30) NOT NULL,
lowerLevel INTEGER NOT NULL,
upperLevel INTEGER NULL,
levelDesc VARCHAR(30) NOT NULL,
CONSTRAINT PK_LevelsTable PRIMARY KEY ( levelType, lowerLevel )
);
INSERT INTO LevelsTable VALUES ( 'pushUps', 0, 10 , 'pathetic' );
INSERT INTO LevelsTable VALUES ( 'pushUps', 10, 15 , 'very weak' );
INSERT INTO LevelsTable VALUES ( 'pushUps', 15, 20 , 'weak' );
INSERT INTO LevelsTable VALUES ( 'pushUps', 20, 30 , 'average' );
INSERT INTO LevelsTable VALUES ( 'pushUps', 30, 40 , 'good' );
INSERT INTO LevelsTable VALUES ( 'pushUps', 40, NULL, 'very good' );
INSERT INTO LevelsTable VALUES ( 'age' , 0, 13 , 'child' );
INSERT INTO LevelsTable VALUES ( 'age' , 13, 20 , 'teenager' );
INSERT INTO LevelsTable VALUES ( 'age' , 20, 55 , 'adult' );
INSERT INTO LevelsTable VALUES ( 'age' , 55, NULL, 'senior' );
输出将是:
SELECT s.idS, s.firstName, s.famillyName
, s.age, a.levelDesc AS ageLevel
, s.pushUps, p.levelDesc AS pushUpLevel
FROM StudentTable s
JOIN LevelsTable a ON a.levelType = 'age'
AND a.lowerLevel <= s.age
AND (a.upperLevel > s.age OR a.upperLevel IS NULL)
JOIN LevelsTable p ON p.levelType = 'pushUps'
AND p.lowerLevel <= s.pushUps
AND (p.upperLevel > s.pushUps OR p.upperLevel IS NULL)
ORDER BY s.idS;
俯卧撑组计数的查询是:
+----+-----------+-------------+-----+----------+---------+-------------+
| idS| firstName | famillyName | age | ageLevel | pushUps | pushUpLevel |
+----+-----------+-------------+-----+----------+---------+-------------+
| 1 | a | d | 17 | teenager | 20 | average |
| 2 | b | e | 18 | teenager | 30 | good |
| 3 | c | f | 19 | teenager | 50 | very good |
+----+-----------+-------------+-----+----------+---------+-------------+
输出将是:
SELECT lvl.lowerLevel AS "from", lvl.upperLevel AS "to"
, lvl.levelDesc AS "level", COUNT(*) AS "students"
FROM StudentTable s
JOIN LevelsTable lvl ON lvl.levelType = 'pushUps'
AND lvl.lowerLevel <= s.pushUps
AND (lvl.upperLevel > s.pushUps OR lvl.upperLevel
GROUP BY lvl.lowerLevel, lvl.upperLevel, lvl.levelDesc
ORDER BY lvl.lowerLevel;
答案 1 :(得分:0)
我不知道sqlite,但MySQL中的方法可能看起来像这样......
DROP TABLE IF EXISTS student_pushups;
CREATE TABLE student_pushups
(student_id INT NOT NULL
,pushups INT NOT NULL
,PRIMARY KEY(student_id)
);
INSERT INTO student_pushups VALUES
(1,20),
(2,30),
(3,50);
DROP TABLE IF EXISTS pushup_levels;
CREATE TABLE pushup_levels
(pushup_quantity INT NOT NULL PRIMARY KEY,level VARCHAR(20) NOT NULL UNIQUE);
INSERT INTO pushup_levels VALUES
(0,'pathetic'),
(10,'very poor'),
(15,'poor'),
(20,'satisfactory'),
(30,'good'),
(40,'very good'),
(50,'excellent');
以下为我们提供了范围...
SELECT x.pushup_quantity range_start
, MIN(COALESCE(y.pushup_quantity,1000))-1 range_end
, x.level
FROM pushup_levels x
LEFT
JOIN pushup_levels y
ON y.pushup_quantity > x.pushup_quantity
GROUP
BY range_start;
+-------------+-----------+--------------+
| range_start | range_end | level |
+-------------+-----------+--------------+
| 0 | 9 | pathetic |
| 10 | 14 | very poor |
| 15 | 19 | poor |
| 20 | 29 | satisfactory |
| 30 | 39 | good |
| 40 | 49 | very good |
| 50 | 999 | excellent |
+-------------+-----------+--------------+
......我们可以加入我们的学生,给我们的结果......
SELECT a.*
, COUNT(b.student_id) total
FROM
( SELECT x.pushup_quantity range_start
, MIN(COALESCE(y.pushup_quantity,1000))-1 range_end
, x.level
FROM pushup_levels x
LEFT
JOIN pushup_levels y
ON y.pushup_quantity > x.pushup_quantity
GROUP
BY range_start
) a
LEFT
JOIN student_pushups b
ON b.pushups BETWEEN a.range_start AND a.range_end
GROUP
BY range_start;
+-------------+-----------+--------------+-------+
| range_start | range_end | level | total |
+-------------+-----------+--------------+-------+
| 0 | 9 | pathetic | 0 |
| 10 | 14 | very poor | 0 |
| 15 | 19 | poor | 0 |
| 20 | 29 | satisfactory | 1 |
| 30 | 39 | good | 1 |
| 40 | 49 | very good | 0 |
| 50 | 999 | excellent | 1 |
+-------------+-----------+--------------+-------+
答案 2 :(得分:-1)
将您的levelstable更改为更像是
id - - 金额 - - 级别
1 - - 10 - - - - - - veryWeak
2 - - 15 - - - - - - 弱
然后只需编写一个简单的查询来选择正确的标签
或者您可以将levelstable放在java枚举中,只需在需要时选择正确的标签。
enum Level{
VeryWeak(10),
Weak(15);
private Integer amount;
Level(Integer amount) {
this.amount= amount;
}
}
根据您的使用情况,可能不需要在表格中定义这些级别。