Home > Software engineering >  query data in four levels tables by laravel eloquent
query data in four levels tables by laravel eloquent

Time:06-05

I have this SQL structure to query schools and the number of student of male gender, I am asking for help for converting it to laravel eloquent

SELECT *
FROM schools && count(students has(gender == 'male'))
JOIN grades ON (grades.schools = schools.school_id)
JOIN streams ON (stream.schools = schools.school_id)
JOIN students ON (student.schools = schools.school_id)

this is what i did in the schemas school schema

 Schema::create('schools', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->string('educationLevel');
            $table->foreignId('ward_id')
            ->constrained('wards')
            ->onUpdate('cascade');
            $table->timestamps();
        });

grade

Schema::create('grades', function (Blueprint $table) {
    $table->id();
    $table->string('name');
    $table->foreignId('school_id')->constrained('schools')
            ->onDelete('cascade');
    $table->timestamps();});

stream

 Schema::create('streams', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->foreignId('grade_id')
            ->constrained('grades')
            ->onDelete('cascade');
            $table->timestamps();
    });

student

Schema::create('students', function (Blueprint $table) {
           $table->id();
            $table->string('student_name');
            $table->string('gender');
            $table->foreignId('stream_id')
            ->constrained('streams')
            ->onDelete('cascade');
            $table->timestamps();
        });

this is what i tried before in school controller

$schools = School::select(['name'])->withCount('students')->where('students', function($query){
    $query->where('gender', 'male');
})
->get();

in school model i did this below

 public function grades()
    {
        return $this->hasMany(Grade::class);
    }

  
    public function students(){
        return $this->hasManyThrough(Student::class, Stream::class, Grade::class);
    }

the relationship of this models is one to many like below school->has->grade->has->stream->student(gender = male or female)

CodePudding user response:

You can leverage addSelect to get the desired output

School::query()
  ->addSelect([
      /** Total no of students in school */
      'count_students' => Student::selectRaw('count(*)')
          ->whereIn(
            'stream_id', 
            Stream::select('id')->whereIn(
              'grade_id',
              Grade::select('id')->whereColumn('school_id', 'schools.id')
            )
          ),
      /** Total no of "gender = male" students in school */
      'count_male' => Student::selectRaw('count(*)')
          ->whereRaw('gender = "male"')
          ->whereIn(
            'stream_id', 
            Stream::select('id')->whereIn(
              'grade_id',
              Grade::select('id')->whereColumn('school_id', 'schools.id')
            )
          ),
      /** Total no of "gender = female" students in school */
      'count_female' => Student::selectRaw('count(*)')
          ->whereRaw('gender = "female"')
          ->whereIn(
            'stream_id', 
            Stream::select('id')->whereIn(
              'grade_id',
              Grade::select('id')->whereColumn('school_id', 'schools.id')
            )
          ),
      /** Total no of "gender = other" students in school */
      'count_other' => Student::selectRaw('count(*)')
          ->whereRaw('gender = "other"')
          ->whereIn(
            'stream_id', 
            Stream::select('id')->whereIn(
              'grade_id',
              Grade::select('id')->whereColumn('school_id', 'schools.id')
            )
          )
  ])->get();

CodePudding user response:

You would need something approaching this:

$schools  = School::Join('grades', 'grades.schools', '=', 'schools.school_id')
            ->Join('stream', 'stream.schools', '=', 'schools.school_id')
            ->Join('student', 'student.schools', '=', 'schools.school_id')
            ->where('gender', "male")
            ->get([
                'name','yourdata'
            ]);

To get the count of data, you simply calculate with count method.

$schoolCount = count($schools);

Make sure your table and column names are appropriate, I am seeing a lot of inconsistencies in your model and table names, same for columns. also, using join you might run into issues like columns with same name. make sure to specify them separately in the get method.Like:

->get([
                'id', 'student.schools as stud', 'stream.name as streamName', 
            ]);
  • Related