SQL循环,条件查询

时间:2018-10-27 03:27:56

标签: sql sqlite

我有包含以下列的表'db':

sname(student name)
cname (course name)
year ( the year when student take)
qtr ( the quarter when student take) : W , S, F (W>S>F)
grade

我想做的是列出每学年每学分增长的学生人数(上一学期<当前的学业平均水平)。学生在宿舍之间可能会有空隙。

SELECT a.sname 
FROM db a
WHERE EXISTS (SELECT * 
              FROM db b
              WHERE a.sname = b.sname 
                AND a.year = b.year 
                AND a.qtr < b.qtr 
                AND a.grade > b.grade)

UNION

合并后,我将处理when a.year > b.year

这就是我现在正在做的-这样正确的方法吗?

我不知道如何在SQL查询中循环...

任何建议将不胜感激。谢谢

1 个答案:

答案 0 :(得分:0)

如果您使用的是当前版本的sqlite(3.25.X),那么使用lag() window函数确实很容易做到。在下面,我使用数字值代替成绩,而不是字母,因为它更容易使用,并假定以下表格定义(基于您的描述)和其中的示例行:

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 时,您表示与 gpa匹配的以前的gpa 每次都增加了[sic]

首先,执行一个查询,该查询计算每个季度的每个学生的GPA,并在每行中也包含前一个GPA(感谢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

如您所见,使用此示例数据,Amy的GPA一直在增加,而Bob却没有。那么,问题是如何只将结果过滤给她?答案在于将HAVINGGROUP 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 ...部分会过滤掉学生中至少有一个行 与前一个相比没有提高的学生。值得花些时间阅读分组知识,因为它可能是最难掌握的基本概念,而且非常有用且功能强大。