protected function get_sql_and_params($count = false) {
        $fields = 'ggh.id, ggh.timemodified, ggh.itemid, ggh.userid, ggh.finalgrade, ggh.usermodified,
                   ggh.source, ggh.overridden, ggh.locked, ggh.excluded, ggh.feedback, ggh.feedbackformat,
                   gi.itemtype, gi.itemmodule, gi.iteminstance, gi.itemnumber, ';

        // Add extra user fields that we need for the graded user.
        $extrafields = get_extra_user_fields($this->context);
        foreach ($extrafields as $field) {
            $fields .= 'u.' . $field . ', ';
        }
        $gradeduserfields = get_all_user_name_fields(true, 'u');
        $fields .= $gradeduserfields . ', ';
        $groupby = $fields;

        // Add extra user fields that we need for the grader user.
        $fields .= get_all_user_name_fields(true, 'ug', '', 'grader');
        $groupby .= get_all_user_name_fields(true, 'ug');

        // Filtering on revised grades only.
        $revisedonly = !empty($this->filters->revisedonly);

        if ($count && !$revisedonly) {
            // We can only directly use count when not using the filter revised only.
            $select = "COUNT(1)";
        } else {
            // Fetching the previous grade. We use MAX() to ensure that we only get one result if
            // more than one histories happened at the same second.
            $prevgrade = "SELECT MAX(finalgrade)
                            FROM {grade_grades_history} h
                           WHERE h.itemid = ggh.itemid
                             AND h.userid = ggh.userid
                             AND h.timemodified < ggh.timemodified
                             AND NOT EXISTS (
                              SELECT 1
                                FROM {grade_grades_history} h2
                               WHERE h2.itemid = ggh.itemid
                                 AND h2.userid = ggh.userid
                                 AND h2.timemodified < ggh.timemodified
                                 AND h.timemodified < h2.timemodified)";

            $select = "$fields, ($prevgrade) AS prevgrade,
                      CASE WHEN gi.itemname IS NULL THEN gi.itemtype ELSE gi.itemname END AS itemname";
        }

        list($where, $params) = $this->get_filters_sql_and_params();

        $sql =  "SELECT $select
                   FROM {grade_grades_history} ggh
                   JOIN {grade_items} gi ON gi.id = ggh.itemid
                   JOIN {user} u ON u.id = ggh.userid
              LEFT JOIN {user} ug ON ug.id = ggh.usermodified
                  WHERE $where";

        // As prevgrade is a dynamic field, we need to wrap the query. This is the only filtering
        // that should be defined outside the method self::get_filters_sql_and_params().
        if ($revisedonly) {
            $allorcount = $count ? 'COUNT(1)' : '*';
            $sql = "SELECT $allorcount FROM ($sql) pg
                     WHERE pg.finalgrade != pg.prevgrade
                        OR (pg.prevgrade IS NULL AND pg.finalgrade IS NOT NULL)
                        OR (pg.prevgrade IS NOT NULL AND pg.finalgrade IS NULL)";
        }

        // Add order by if needed.
        if (!$count && $sqlsort = $this->get_sql_sort()) {
            $sql .= " ORDER BY " . $sqlsort;
        }

        return array($sql, $params);
    }