我有一个学院学校的数据库。它的结构有三个表: - 第一个是科目硕士。这个表可能有20多行。
CREATE TABLE `SUBJECTS` (
`ID_SB` tinyint(4) NOT NULL AUTO_INCREMENT,
`NAME` varchar(255) DEFAULT NULL,
PRIMARY KEY (`ID_SB`)
)
- 第二个包含学生数据。这个可能有10000多行。
CREATE TABLE `STUDENTS` (
`ID_ST` int(10) NOT NULL AUTO_INCREMENT,
`NAME` varchar(50) DEFAULT NULL,
PRIMARY KEY (`ID_ST`)
)
- 最后一个具有学生对每个科目的资格。它有大约1000行。
CREATE TABLE `QUALIFICATIONS` (
`ID_CF` int(10) NOT NULL AUTO_INCREMENT,
`ID_ST` int(10) DEFAULT NULL,
`ID_SB` int(10) DEFAULT NULL,
`VALUE` int(2) DEFAULT NULL,
PRIMARY KEY (`ID_CF`)
)
我需要以excel格式导出所有这些数据,例如:
Id:st / Name / Subject1/ Subject2/ Subject3/ Subject4/..../Subject_N
(如果一个学生没有某个科目的资格,则excel显示此专栏的空单元格。)
我如何加入所有这些表格?我考虑过使用LEFT JOIN,但此查询的返回行数呈指数增长。
现在我的问题比以前更糟了,因为我必须添加与1:N基数的学生相关的新表。
我该如何改进此功能?我无法更改数据库架构。
由于
答案 0 :(得分:1)
我想你忘了GROUP BY
,请尝试以下方法。
SELECT
ST.ID_ST, ST.`NAME`, GROUP_CONCAT(DISTINCT SU.`NAME`) AS subjects
FROM STUDENTS AS ST
LEFT JOIN QUALIFICATIONS AS QU ON
ST.ID_ST = QU.ID_ST
LEFT JOIN SUBJECTS AS SU ON
SU.ID_SB = QU.ID_SB
GROUP BY ST.ID_ST
这应该只显示每个学生一次,主题应该用逗号(,)分隔,每个主题应该只出现一个学生一次(但只有学生有主题)。
ID - 姓名 - 主题
1 - Eve - Subj1,Subj3,Subj7
但是,这不是你要求的,你希望每个主题都拥有它自己的专栏,对吗?
为此,您可以在选择中使用subquery
来获取所有主题,并使用IF
为每个主题打印是或否。您仍然需要使用GROUP_CONCAT
。但我会以不同的方式解决它。
我会使用不同的语言来分隔列。首先,您需要所有学生科目的学生信息和ID,如下所示:
SELECT
ST.ID_ST, ST.`NAME`, GROUP_CONCAT(DISTINCT QU.`ID_SB`) AS subject_ids
FROM STUDENTS AS ST
LEFT JOIN QUALIFICATIONS AS QU ON
ST.ID_ST = QU.ID_ST
GROUP BY ST.ID_ST
然后得到主题:
SELECT * FROM SUBJECTS
最后一部分是创建Excel。下面的例子是用PHP编写的:
$excelRows = array();
foreach($students as $student){
$excelRow = array($student->id, $student->name);
foreach($subjects as $subject){
array_push($excelRow, (in_array($subject->id, $student->subject_ids))?'yes':'no');
}
array_push($excelRows, $excelRow);
}
所以,我们只是循环学生,在学生循环中我们循环主题。
它没有经过测试,但我认为大部分都应该有效。如果失败了,请告诉我你的尝试并解释它为什么不起作用。