【问题标题】:Group by on Varchar field messing up分组按 Varchar 字段搞砸
【发布时间】:2018-10-21 09:12:45
【问题描述】:

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

在此表中,第 1 行代表学生在第一季度所修读的课程。同样,第 2 行代表第二季度的课程。与第 3 行和第 4 行相同。我想提取课程和成绩的整体列表。课程的成绩应该是最后一次参加该课程的成绩。所以,结果数据表应该如下:

我已经通过查询编写了以下组:

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) 正在返回科目“数学”的错误成绩。有没有其他方法可以实现结果?

【问题讨论】:

  • 你是如何生成 row_number 的?
  • 我发现您想要的结果与输入数据之间没有任何关系。
  • Row_number 由 Partition 生成。
  • 跳转到sqlfiddle.comrextester.com 整理数据
  • 我想提取学生跨季度学习的不同课程。他们的成绩是学生@上次参加课程时获得的成绩。有意义吗?

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


【解决方案1】:

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

一种方法是使用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 中的原始样本数据在课程名称中有标签,我将其替换为空格。

查询

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
;

【讨论】:

  • 哇,这正是我想要的。谢谢!!
  • 不客气。如果你想通过比较和很多细节来学习其他方法,看看这个问题:Retrieving n rows per group
【解决方案2】:

您当前的查询旨在列出最高成绩,而不是最新成绩。

如果你想获得学生的最新成绩,你不应该使用 Max() 选择最高值。

我可以看到您的 ROWNUM 可能会帮助您在课程中获得时间顺序,所以我建议您为每个在 ROWNUM 上具有最高价值的科目列出一行。

例如,如果我们查看历史记录,它最后记录在 ROWNUM 2 上,那么它的最高时间值将是 2(而 Math 是 4)。然后,作为最终结果,您可以显示第 2 行的历史成绩、第 4 行的数学等。这样您就只能获得最新的成绩。

P.S :这仅适用于一个 ROWNUM 没有两个相同主题的情况,因此它可能不是进一步更改表的最佳解决方案。

【讨论】:

  • 你能在 fiddler 中演示这个吗?
  • @Rick 我从来没有用过提琴手,所以我用你以前的 SQL 工具来说明我的意思:rextester.com/WTBKJ25044
  • 另外,我发现您将制表符放在 VARCHAR 分隔符内,这导致您的其他 varchars 'math' 与您的第一个 'math' 不同,这个不包含制表符。您不必添加任何内容,因为 varchar 将自行管理长度。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-06-07
  • 2019-08-08
  • 1970-01-01
  • 2012-12-27
  • 1970-01-01
  • 2013-11-18
相关资源
最近更新 更多