学生表:存储学生的基本信息
fee_received 表:存储每年每个月每个学生支付的每月学费的信息。
问题:
我需要让所有在2018年最后7个月内成为Fee_defaulters的学生。最重要的是,我需要为每个学生提供所有这些月(例如:3、4、6),以便我可以向管理员显示学生是哪个月份的费用拖欠者。
表架构
CREATE TABLE `fee_received` (
`id` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
`challan_no` int(11) NOT NULL DEFAULT '0',
`student_id` int(11) NOT NULL,
`class_id` int(2) NOT NULL,
`amount` int(5) NOT NULL,
`arrears` int(6) NOT NULL DEFAULT '0' COMMENT 'arrears in monthly tuition fee.',
`fine` int(11) NOT NULL DEFAULT '0' COMMENT 'total fine in current challan',
`fee_month` int(2) NOT NULL,
`fee_year` int(4) NOT NULL,
`dt` date NOT NULL,
`multi_fee` tinyint(11) NOT NULL DEFAULT '0',
`submitted_with_admission` tinyint(1) NOT NULL DEFAULT '0',
`status` tinyint(1) NOT NULL DEFAULT '1' COMMENT '1 = received , 2 = pending, 3 = deleted'
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
CREATE TABLE `student` (
`id` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
`reg_no` int(11) NOT NULL,
`name` varchar(50) NOT NULL,
`f_name` varchar(50) NOT NULL,
`cnic1` varchar(20) DEFAULT NULL,
`cnic` varchar(20) DEFAULT NULL,
`caste` varchar(50) DEFAULT NULL,
`occupation` varchar(100) DEFAULT NULL,
`dob` date NOT NULL,
`gender` enum('M','F','O','') NOT NULL DEFAULT 'M',
`contact` varchar(13) NOT NULL,
`address` varchar(500) NOT NULL,
`admission_id` int(11) DEFAULT '0'
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
当前未优化的解决方案: 注意:我已经简化了StackOverflow的解决方案,只是为了显示问题区域
以下sub_query获取所有已支付全部7个月费用的学生。
$already_paid_student_ids_query = "SELECT t.student_id
FROM (
SELECT COUNT(*) AS count, student_id
FROM fee_received
WHERE fee_month IN (1, 2, 3, 4, 5, 6, 7)
AND fee_year = 2018
AND class_id = 10
AND status = 1
GROUP BY student_id
) AS t
WHERE t.count >= 7";
然后,我有以下主要查询,这给了我所有拖欠费用的学生。
$fee_defaulters_query = "SELECT student.* FROM student
WHERE student.id NOT IN ( {$already_paid_student_ids_query} )";
到此为止,我已经收到所有违约费用。但是我不知道哪个学生哪个月是费用拖欠者。因此,我应用了一个非常昂贵的解决方案。
我已经遍历了每个费用拖欠者,并要求Fee_received表为该学生获得几个月的费用。
$paid_months_query = "SELECT fee_month FROM fee_received WHERE student_id = {$student_id} AND fee_year = {$fee_year} AND fee_month IN (1,2,3,4,5,6,7) AND status = 1 ";
然后使用一些编程,我得到了每个学生的无薪月份,并显示给管理员。
必需的解决方案
我需要摆脱循环内的查询。并且需要一种解决方案,这样我就可以在单个查询中获得所有fee_defaulter学生和每个学生的无薪月份列表。
SQL小提琴链接 link
答案 0 :(得分:1)
您希望每个学生在某些月份付款。因此,将所有月份与所有学生结合在一起。然后查看缺少付款的地方。
select student.id as student_id, months.year, months.month
from
(
select 2018 as year, 1 as month
union all
select 2018 as year, 2 as month
union all
select 2018 as year, 3 as month
union all
select 2018 as year, 4 as month
union all
select 2018 as year, 5 as month
union all
select 2018 as year, 6 as month
union all
select 2018 as year, 7 as month
) months
cross join student
where (student.id, months.year, months.month) not in
(
select student_id, fee_year, fee_month
from fee_received
where class_id = 10
and status = 1
)
order by student_id, months.year, months.month;
(我只是从您的查询中复制了class_id条件。如果这是并非所有学生都参加的特定课程,那么您可能希望以某种方式限制学生-可能使用一些您未提及的student_class表。)
如果您希望每个学生一行,那么您必须进行汇总:
select
student.id as student_id,
group_concat(concat(months.year, '/', months.month)) as unpaid_months
from
(
select 2018 as year, 1 as month
union all
select 2018 as year, 2 as month
union all
select 2018 as year, 3 as month
union all
select 2018 as year, 4 as month
union all
select 2018 as year, 5 as month
union all
select 2018 as year, 6 as month
union all
select 2018 as year, 7 as month
) months
cross join student
where (student.id, months.year, months.month) not in
(
select student_id, fee_year, fee_month
from fee_received
where class_id = 10
and status = 1
)
group by student.id
order by student.id;
答案 1 :(得分:1)
我创建了一个SQL Fiddle,该SQL Fiddle生成了一个缺少付款的学生列表。它还显示他们支付了哪些月份。
MySQL 5.6模式设置:
CREATE TABLE `fee_received` (
`id` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
`challan_no` int(11) NOT NULL DEFAULT '0',
`student_id` int(11) NOT NULL,
`class_id` int(2) NOT NULL,
`amount` int(5) NOT NULL,
`arrears` int(6) NOT NULL DEFAULT '0' COMMENT 'arrears in monthly tuition fee.',
`fine` int(11) NOT NULL DEFAULT '0' COMMENT 'total fine in current challan',
`fee_month` int(2) NOT NULL,
`fee_year` int(4) NOT NULL,
`dt` date NOT NULL,
`multi_fee` tinyint(11) NOT NULL DEFAULT '0',
`submitted_with_admission` tinyint(1) NOT NULL DEFAULT '0',
`status` tinyint(1) NOT NULL DEFAULT '1' COMMENT '1 = received , 2 = pending, 3 = deleted'
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
CREATE TABLE `student` (
`id` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
`reg_no` int(11) NOT NULL,
`name` varchar(50) NOT NULL,
`f_name` varchar(50) NOT NULL,
`cnic1` varchar(20) DEFAULT NULL,
`cnic` varchar(20) DEFAULT NULL,
`caste` varchar(50) DEFAULT NULL,
`occupation` varchar(100) DEFAULT NULL,
`dob` date NOT NULL,
`gender` enum('M','F','O','') NOT NULL DEFAULT 'M',
`contact` varchar(13) NOT NULL,
`address` varchar(500) NOT NULL,
`admission_id` int(11) DEFAULT '0'
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
INSERT INTO `student`
(`reg_no`, `name`, `f_name`, `cnic1`, `cnic`, `caste`, `occupation`, `dob`, `gender`, `contact`, `address`, `admission_id`)
VALUES
(1123,'John Doe','John','1','1','1','student','2000-05-01','M','123-456-7890','123 S Western Ave',123),
(1533,'Jane Doe','Jane','1','1','1','student','2000-05-01','F','123-456-7890','123 S Western Ave',123),
(2341,'Fred Smith','Fred','1','1','1','student','2000-05-01','M','123-456-7890','123 S Western Ave',123),
(6541,'Tanya Edilstien','Tanya','1','1','1','student','2000-05-01','M','123-456-7890','123 S Western Ave',123);
INSERT INTO `fee_received`
(`challan_no`, `student_id`, `class_id`, `amount`, `arrears`, `fine`, `fee_month`, `fee_year`, `dt`, `multi_fee`, `submitted_with_admission`, `status`)
VALUES
(1,1,1,123,0,0,1,2018,'2018-01-04',0,0,1),
(1,1,1,123,0,0,2,2018,'2018-02-04',0,0,1),
(1,1,1,123,0,0,3,2018,'2018-03-04',0,0,1),
(1,1,1,123,0,0,4,2018,'2018-04-04',0,0,1),
(1,1,1,123,0,0,5,2018,'2018-05-04',0,0,1),
(1,1,1,123,0,0,6,2018,'2018-06-04',0,0,1),
(1,1,1,123,0,0,7,2018,'2018-07-04',0,0,1),
(2,2,2,123,0,0,1,2018,'2018-01-04',0,0,1),
(2,2,2,123,0,0,4,2018,'2018-04-04',0,0,1),
(2,2,2,123,0,0,5,2018,'2018-05-04',0,0,1),
(2,2,2,123,0,0,6,2018,'2018-06-04',0,0,1),
(2,2,2,123,0,0,7,2018,'2018-07-04',0,0,1),
(3,3,3,123,0,0,1,2018,'2018-01-04',0,0,1),
(3,3,3,123,0,0,2,2018,'2018-02-04',0,0,1),
(3,3,3,123,0,0,3,2018,'2018-03-04',0,0,1),
(3,3,3,123,0,0,4,2018,'2018-04-04',0,0,1),
(3,3,3,123,0,0,5,2018,'2018-05-04',0,0,1),
(3,3,3,123,0,0,7,2018,'2018-07-04',0,0,1),
(4,4,4,123,0,0,1,2018,'2018-01-04',0,0,1),
(4,4,4,123,0,0,2,2018,'2018-02-04',0,0,1),
(4,4,4,123,0,0,3,2018,'2018-03-04',0,0,1),
(4,4,4,123,0,0,4,2018,'2018-04-04',0,0,1),
(4,4,4,123,0,0,5,2018,'2018-05-04',0,0,1),
(4,4,4,123,0,0,6,2018,'2018-06-04',0,0,1),
(4,4,4,123,0,0,7,2018,'2018-07-04',0,0,1);
查询1 :
select
a.`id`,
a.`name`,
a.`contact`,
a.`address`,
count(b.`id`) as `num_payments`,
GROUP_CONCAT(b.`fee_month` ORDER BY b.`fee_month`) as `Months_Paid`
FROM `student` a
LEFT JOIN `fee_received` b
ON a.`id` = b.`student_id` AND b.`status` = 1 AND b.`dt` BETWEEN '2018-01-01' AND '2018-07-31'
GROUP BY a.`id`
HAVING `num_payments` < 7
Results :
| id | name | contact | address | num_payments | Months_Paid |
|----|------------|--------------|-------------------|--------------|-------------|
| 2 | Jane Doe | 123-456-7890 | 123 S Western Ave | 5 | 1,4,5,6,7 |
| 3 | Fred Smith | 123-456-7890 | 123 S Western Ave | 6 | 1,2,3,4,5,7 |