0

I have a DB table students with all the subjects final grades for each subject what is quite a number, and a number of other fields, like name, etc.

students (table is having more than 100 columns, each cell can have some pre-set ID, which later is translated to grades /some silly anti-hacking technique, where several numbers can represent the same grade/)

|| name  || surname|| section || math1||math 2||math 16|| physics 1||physics 2 ||... ||
|| Jonah || Smith  ||  A4     || 17   || 19   || 0     || 193      ||          ||    
|| John  ||Doe     ||  A3     ||  0   || 0    || 34    ||12        ||  0       || ...||
|| Jane  ||Doe     ||  A3     ||  0   || 0    || 48    ||12        ||  154     || ...||
|| Martin||Doe     ||  A3     || 17   || 34   || 96    ||10        || 225      || ...||

DESIRABLE RESULT

|| avg.grade || name  || surname|| section || math1||math 2||math 16|| physics 1||physics 2||... ||
|| 0.92      || John  ||Doe     || A3      ||0   || 0    ||...    ||12        || 0       || ...||
|| 0.81      || Jane  ||Doe     || A3      ||0   || 0    ||...    ||12        || 154     || ...||

There are literally NO other related tables, except for

  • auxiliary in memory table with grades to IDs representation
  • subjects and students' data

I want to get selected (using Laravel eloquent model) all the fields AND 'final grade', what is summ for all the selected ... above some threshold. (The presented below

SELECT *, a FROM `students` WHERE 
`name` LIKE "J%" AND `surname` LIKE "D" AND `section` = 'A3'
enter code here
AND (if(`math16`='12',0.76, 0)
+if(`geometry26`='13',0.76, 0) +if(`physics13`='325',1, 0)
+if(`programming06`='551',1, 0) +if(`biology18`='271',0.916, 0) 
+ .... )/18.216 as a > 0.75

'12','13','25','551','271' - are codes of grades.

Technically, I need to get all the students, who got more or less the same courses with some average grades for a given starting letter of name. (I mean, If I have John, who took specific courses [math16 with grade 0.76,biology18 with grade 0.91,...] and Jane [math16 with grade 0.76,programming06 with grade 100,...], I'd like to get their records together, with a sum of their grades, without the rest of students.

Probably, there is some other possibility to get all the rows with somehow identical fields together, but I cannot get how can I do so. Thanks

Alexey Abraham
  • 379
  • 2
  • 13
  • Could you provide a sample of the `students` table/model with records, and how is your desired output? At the moment, it isn't very clear. – Kenny Horna Feb 17 '19 at 21:11
  • 1
    I meant update your question with a sample with data, your sql statement it isn't really helpful (imo). Also your related tables (subject, ...) – Kenny Horna Feb 17 '19 at 21:14
  • @HCK, added some tables – Alexey Abraham Feb 17 '19 at 21:35
  • @DCR: Specific recommendations for how the original poster can improve his question are welcome, but unhelpful scolding the OP is not. – Hovercraft Full Of Eels Feb 17 '19 at 21:48
  • I think you should model your database a little bit different to decouple your columns. Having >100 columns in the student table it isn't very useful, this becuse -I assume- students doesn't take all those courses at the same time. You could have a students table (with basic student information), then a subject table, with all the grades related to this course and also specifying the algorithm tha determine the actual grade to apply to that course maybe... then another table in where you relate the student with the courses of a specific semester/course period – Kenny Horna Feb 17 '19 at 21:54
  • @HCK, all this question is not about students and subjects. Due to NDA I cannot provide real issue. I've thought of remodelling the DB, but all other results gave drastic decrease in the requests speed. – Alexey Abraham Feb 17 '19 at 22:05

2 Answers2

1

I would not recommend keeping the subjects in the students table, instead you should explore normalizing your database a bit further and adding a subjects and student_subject table. However with your current setup, you could consider creating the attribute on the model, and then appending it.

https://laravel.com/docs/5.7/eloquent-serialization#appending-values-to-json

class User {

    protected $appends = [
        'average_grade'
    ];

    public function getAverageGradeAttribute()
    {
        return $this->attributes['average_grade'] = ($this->math1 + $this->math2) / 2;
    }

}

Doing so will allow you to simply call the attribute while displaying it in your view, like so:

<table>
    <thead>
        <tr>
            <th>Student</th>
            <th>Average Grade</th>
        </tr>
    </thead>
    <tbody>
        @foreach($students as $student)
            <tr>
                <td>{{ $student->name }}</td>
                <td>{{ $student->average_grade }}</td>
            </tr>
        @endforeach
    </tbody>
</table>
Ian C
  • 141
  • 1
  • 10
  • Thanks, 1. I don't know how to refactor/normalize the table. The reason: the pre-set of subjects is not so big and quite dense. 2. I've thought to do so, adding an attribute, but the request is just one from about zillion (ok, not zillion, but ~20 :)). And for some reason I was sure, adding an attribute would affect every query. Looks I was wrong thanks – Alexey Abraham Feb 17 '19 at 21:56
  • Also, 3. it is not about subjects and students, but due to NDA I have to rephrase my question :) 4.Looks I'm to do calculations inside where clause. Otherwise it is very time consuming. I have thousands of records – Alexey Abraham Feb 17 '19 at 22:01
  • No problem Alexey. The most effective thing you could do is normalize your database. It is going to be extremely time consuming for you to do it later on, and is only going to inhibit you from scaling your application. – Ian C Feb 17 '19 at 22:04
  • Ian, this table already has dozens of thousands of records %). and I have no clue how to normalize it without ruining all the rest ^_^. – Alexey Abraham Feb 17 '19 at 22:10
  • - 'student`s record' is just one 'brick' in the system. Every field of which is encrypted. And only inside this specific query we have access to SOME of fields, to be able to decrypt them and calculate some result. – Alexey Abraham Feb 17 '19 at 22:13
  • Yikes. Well something else you could consider is adding a `average_grade` column to the `students` table and then populating it overnight (or twice daily, etc) using a task. That way you don't have to worry about calculations on the fly. – Ian C Feb 17 '19 at 22:14
  • Thanks, that is not an option: we get criteria for the select only when we need to select, not a minute prior the case. – Alexey Abraham Feb 18 '19 at 03:21
0

You can do the following to achieve your purpose. Assuming you want to get the sum total of individual summations of 2 fields in the table where the field names are field1 and field2 for the table whose model name is 'ModelName' then you can do the following:

$amount = ModelName::select(DB::raw('sum(field1 + field2) as total'))->get();
Dharman
  • 30,962
  • 25
  • 85
  • 135
Dibyendu Mitra Roy
  • 1,604
  • 22
  • 20