sql - 按 Varchar 字段分组

标签 sql sql-server join group-by common-table-expression

我的项目中有下表数据。该表按行号分区。

Available data table

在此表中,行号 1 表示学生在第一季度修读的类(class)。同样,行号 2 代表第二季度的类(class)。与第 3 行和第 4 行相同。我想提取类(class)和成绩的总体列表。类(class)的成绩应该是最后一次参加该类(class)的成绩。所以,结果数据表应该是这样的:

Expected result table

我写了下面的组查询:

SELECT
    T.NAME,
    T.COURSE,
    T.HRSCODE,
    MAX(T.GRADE) as 'GRADE'
FROM 
    #TEMP T 
GROUP BY 
    T.NAME, T.COURSE, T.HRSCODE

演示:rextester.com/FSUIM64308

MAX(grade) 返回主题“数学”的错误成绩。有没有其他方法可以完成这个结果?

最佳答案

这看起来像是一个经典的每组 top-n 问题。

一种方法是使用 ROW_NUMBER 函数。

示例数据

CREATE TABLE TEMP1(ROWNUM INT,
NAME VARCHAR(50), COURSE VARCHAR(50), year int,
CAT VARCHAR(50), HRSCODE VARCHAR(30), GRADE VARCHAR(10))

insert TEMP1 values
    ('1' ,  'STUDENT1' ,    'MATH       ' , 2016,'CRS1' ,'MT1.Y7'  , 'A+'),
    ('1' ,  'STUDENT1' ,    'ENGLISH    ' , 2016,'CRS2' ,'ENG14.JI', 'B'),
    ('1' ,  'STUDENT1' ,    'SCIENCE    ' , 2016,'CRS3' ,'SCI678'  , 'C'),
    ('1' ,  'STUDENT1' ,    'HISTORY    ' , 2016,'CRS4' ,'HIS704'  , 'A+'),
    ('2' ,  'STUDENT1' ,    'MATH       ' , 2016,'CRS1' ,'MT1.Y7'  , 'A-'),
    ('2' ,  'STUDENT1' ,    'ENGLISH    ' , 2016,'CRS2' ,'ENG14.JI', 'B+'),
    ('2' ,  'STUDENT1' ,    'SCIENCE    ' , 2016,'CRS3' ,'SCI678'  , 'C+'),
    ('2' ,  'STUDENT1' ,    'HISTORY    ' , 2016,'CRS4' ,'HIS704'  , 'C-'),
    ('3' ,  'STUDENT1' ,    'MATH       ' , 2017,'CRS1' ,'MT1.Y7'  , 'A+'),
    ('3' ,  'STUDENT1' ,    'ENGLISH    ' , 2017,'CRS2' ,'ENG14.JI', 'A+'),
    ('3' ,  'STUDENT1' ,    'PSYCHOLOGY ' , 2017,'CRS3' ,'PSY9.78' , 'B'),
    ('3' ,  'STUDENT1' ,    'PHYSICS    ' , 2017,'CRS4' ,'PHY53.XG', 'B'),
    ('4' ,  'STUDENT1' ,    'MATH       ' , 2017,'CRS1' ,'MT1.Y7'  , 'A'),
    ('4' ,  'STUDENT1' ,    'ENGLISH    ' , 2017,'CRS2' ,'ENG14.JI', 'C'),
    ('4' ,  'STUDENT1' ,    'PSYCHOLOGY ' , 2017,'CRS3' ,'PSY9.78' , 'B'),
    ('4' ,  'STUDENT1' ,    'PHYSICS    ' , 2017,'CRS4' ,'PHY53.XG', 'C+');

请注意,您在 rextester 中的原始示例数据在类(class)名称中有制表符,我将其替换为空格。

查询

SELECT TOP(1) WITH TIES
    NAME
    ,COURSE
    ,year
    ,CAT
    ,HRSCODE
    ,GRADE
FROM TEMP1
ORDER BY ROW_NUMBER() OVER (PARTITION BY NAME, COURSE ORDER BY year DESC,  ROWNUM DESC)
;

http://rextester.com/edit/KQKP45357

结果

+----+----------+-------------+------+------+----------+-------+
|    |   NAME   |   COURSE    | year | CAT  | HRSCODE  | GRADE |
+----+----------+-------------+------+------+----------+-------+
|  1 | STUDENT1 | ENGLISH     | 2017 | CRS2 | ENG14.JI | C     |
|  2 | STUDENT1 | MATH        | 2017 | CRS1 | MT1.Y7   | A     |
|  3 | STUDENT1 | HISTORY     | 2016 | CRS4 | HIS704   | C-    |
|  4 | STUDENT1 | PHYSICS     | 2017 | CRS4 | PHY53.XG | C+    |
|  5 | STUDENT1 | PSYCHOLOGY  | 2017 | CRS3 | PSY9.78  | B     |
|  6 | STUDENT1 | SCIENCE     | 2016 | CRS3 | SCI678   | C+    |
+----+----------+-------------+------+------+----------+-------+

这个查询更常见的写法是这样的:

WITH
CTE
AS
(
    SELECT
        ROWNUM
        ,NAME
        ,COURSE
        ,year
        ,CAT
        ,HRSCODE
        ,GRADE
        ,ROW_NUMBER() OVER(PARTITION BY NAME, COURSE ORDER BY year DESC, ROWNUM DESC) AS rn
    FROM TEMP1
)
SELECT
    NAME
    ,COURSE
    ,year
    ,CAT
    ,HRSCODE
    ,GRADE
FROM CTE
WHERE rn = 1
ORDER BY NAME, COURSE
;

关于sql - 按 Varchar 字段分组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50284070/

相关文章:

mysql - 在mysql中转换mssql触发器

linux - 匹配不同文件中的 2 个字段

mysql - 获取错误 SQL Server 子查询返回超过 1 个值。当子查询跟在=、!=、<、<=、>、>=之后时,这是不允许的

mysql - 使用内连接SQL语句时未定义索引

mysql - 选择随机行时的 SQL Join 帮助

mysql - 在同一查询中重用计算字段以进行新计算

SQL 按周分组包括计数为 0 的周

sql - 选择从,创建没有标识属性的表

c# - DbMigration.AlterstoredProcedure( Entity Framework 迁移): How to represent type smallmoney?

sql - 如何提高 SQL Server 中日期时间过滤的性能?