Если вы используете текущую версию sqlite (3.25.X), это действительно легко сделать с помощью оконной функции lag()
. Ниже я использую числовые значения для оценок вместо букв, потому что с ними гораздо проще работать, и предполагаю следующее определение таблицы (на основе вашего описания) и примеры строк в ней:
CREATE TABLE IF NOT EXISTS grades(
sname TEXT NOT NULL
, year INTEGER NOT NULL
, qtr INTEGER NOT NULL
, cname TEXT NOT NULL
, grade NUMERIC
, PRIMARY KEY (sname, year, qtr, cname)
) WITHOUT ROWID;
INSERT INTO grades(sname, cname, year, qtr, grade) VALUES
('Bob', 'Math', 2017, 3, 2.0), ('Bob', 'Math', 2017, 4, 2.5),
('Bob', 'Math', 2018, 1, 3.0), ('Amy', 'Math', 2017, 3, 4.0),
('Amy', 'Math', 2017, 4, 3.5), ('Amy', 'Math', 2018, 1, 4.0),
('Bob', 'History', 2017, 3, 3.5), ('Bob', 'History', 2017, 4, 3.0),
('Bob', 'History', 2018, 1, 3.5), ('Amy', 'History', 2017, 3, 2.5),
('Amy', 'History', 2017, 4, 3.5), ('Amy', 'History', 2018, 1, 4.0);
Я предполагаю, что, когда вы сказали предыдущий класс <текущий gpa </em>, вы имели в виду предыдущий gpa , чтобы соответствовать gpa, увеличивалось каждую квартал [sic] .
Во-первых, запрос, который вычисляет средний балл каждого студента за каждый квартал и включает в себя предыдущий средний балл в каждой строке (спасибо lag()
):
SELECT sname, year, qtr
, avg(grade) AS gpa
, lag(avg(grade), 1, 0.0)
OVER (PARTITION BY sname ORDER BY year, qtr) AS prev_gpa
FROM grades
GROUP BY sname, year, qtr
ORDER BY sname, year, qtr;
Это производит:
sname year qtr gpa prev_gpa
---------- ---------- ---------- ---------- ----------
Amy 2017 3 3.25 0.0
Amy 2017 4 3.5 3.25
Amy 2018 1 4.0 3.5
Bob 2017 3 2.75 0.0
Bob 2017 4 2.75 2.75
Bob 2018 1 3.25 2.75
Как видите, с этими примерами данных у Эми постоянно увеличивается средний балл, а у Боба - нет. Итак, вопрос в том, как отфильтровать результаты только для нее? Ответ на этот вопрос заключается в использовании HAVING
с GROUP BY
. Это немного усложняется тем, что значения, вычисленные оконными функциями, могут появляться только в списке столбцов выбора и предложениях ORDER BY
, поэтому я вставляю приведенный выше запрос в CTE , чтобы обойти это ограничение:
WITH gpas AS (
SELECT sname, year, qtr
, avg(grade) AS gpa
, lag(avg(grade), 1, 0.0)
OVER (PARTITION BY sname ORDER BY year, qtr) AS prev_gpa
FROM grades
GROUP BY sname, year, qtr)
SELECT sname
FROM gpas
GROUP BY sname
HAVING sum(CASE WHEN gpa > prev_gpa THEN 1 ELSE 0 END) = count(gpa)
ORDER BY sname;
, который производит
sname
----------
Amy
Партия GROUP BY sname HAVING ...
отфильтровывает студентов, у которых хотя бы в одной из строк нет повышенного среднего балла по сравнению с предыдущим. Стоит потратить некоторое время на чтение групп, так как это, пожалуй, самая сложная базовая концепция, а также очень полезная и мощная.