php - 优化高级SQL查询

标签 php mysql

表格信息 enter image description here 我有以下表格及其目的:

student表:存储学生的基本信息

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 的解决方案,只是为了显示问题区域

以下子查询获取所有 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 Fiddle 链接 link

最佳答案

我创建了一个 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 |

关于php - 优化高级SQL查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51800750/

相关文章:

php - 我该如何做这个sql过滤结果

php - 使用 Mockery 模拟在另一个静态方法中调用的静态方法

php - 将 PHP 关联数组传递给 JavaScript 时出错

php - 只是想知道为什么这不起作用,我想将数据从提交表单插入到数据库

php - MySQL 3表连接user_id,没有得到NULL值,而是重复的条目

php - laravel4 迁移失败(pdo 异常)

php - 从 PHP 中的字符串输入中删除特定字符串

mysql - 加入 1 对 1 表总是必要的吗?

php - 使用 php password_hash 函数更新 md5 密码

mysql - 环回自定义查询未给出响应