单个查询中有多个MAX值

时间:2017-06-08 14:59:05

标签: sql sql-server sql-server-2008

我正在将此数据作为转换过程的一部分插入另一个表中。不幸的是,我无法在源位置或目标位置修改表架构。

架构如下(超级简化,但数据类型不能修改,只是显然是强制转换)

NullPointerException

我有以下源数据:(显然只是一个人的数据快照)

CREATE TABLE [dbo].[TestScores](
    [id] [INT] NOT NULL,
    [EXAMNE_ID] [VARCHAR](40) NULL,
    [TestName] VARCHAR(30) NULL,
    [PASS_STA] [VARCHAR](5) NULL,
    [TST_DTE] [VARCHAR](8) NULL,
    [STD_SCOR] [VARCHAR](3) NULL,
) ON [PRIMARY]

我的最终结果目标数据应如下所示:

+----+-----------+-----------------+----------+----------+----------+
| id | EXAMNE_ID |    TestName     | PASS_STA | TST_DTE  | STD_SCOR |
+----+-----------+-----------------+----------+----------+----------+
|  1 |     00001 | Social Studies  | Fail     | 20160608 |        7 |
|  2 |     00001 | Science         | Fail     | 20160608 |        8 |
|  3 |     00001 | Reading         | Fail     | 20160608 |        2 |
|  4 |     00001 | Math            | Fail     | 20160608 |        8 |
|  5 |     00001 | Writing         | Fail     | 20160608 |        7 |
|  6 |     00001 | Social Studies  | Fail     | 20160608 |        7 |
|  7 |     00001 | Science         | Fail     | 20160608 |        8 |
|  8 |     00001 | Reading         | Fail     | 20160608 |        2 |
|  9 |     00001 | Math            | Fail     | 20160608 |        8 |
| 10 |     00001 | Writing         | Fail     | 20160608 |        7 |
| 11 |     00001 | Social Studies  | Fail     | 20160608 |        7 |
| 12 |     00001 | Science         | Fail     | 20160608 |        8 |
| 13 |     00001 | Reading         | Fail     | 20160608 |        2 |
| 14 |     00001 | Math            | Fail     | 20160608 |        8 |
| 15 |     00001 | Writing         | Fail     | 20160608 |        7 |
| 16 |     00001 | Social Studies  | Fail     | 20160608 |        7 |
| 17 |     00001 | Social Studies  | Fail     | 20160930 |       10 |
| 18 |     00001 | Science         | Fail     | 20160608 |        8 |
| 19 |     00001 | Reading         | Fail     | 20160608 |        2 |
| 20 |     00001 | Reading         | Fail     | 20160930 |        5 |
| 21 |     00001 | Math            | Fail     | 20160608 |        8 |
| 22 |     00001 | Writing         | Fail     | 20160608 |        7 |
| 23 |     00001 | Writing         | Fail     | 20160930 |       10 |
| 24 |     00001 | Social Studies  | Fail     | 20160608 |        7 |
| 25 |     00001 | Social Studies  | Fail     | 20160930 |       10 |
| 26 |     00001 | Science         | Fail     | 20160608 |        8 |
| 27 |     00001 | Reading         | Fail     | 20160608 |        2 |
| 28 |     00001 | Reading         | Fail     | 20160930 |        5 |
| 29 |     00001 | Math            | Fail     | 20160608 |        8 |
| 30 |     00001 | Writing         | Fail     | 20160608 |        7 |
| 31 |     00001 | Writing         | Fail     | 20160930 |       10 |
| 32 |     00001 | Social Studies  | Fail     | 20160608 |        7 |
| 33 |     00001 | Social Studies  | Fail     | 20160930 |       10 |
| 34 |     00001 | Science         | Fail     | 20160608 |        8 |
| 35 |     00001 | Reading         | Fail     | 20160608 |        2 |
| 36 |     00001 | Reading         | Fail     | 20160930 |        5 |
| 37 |     00001 | Math            | Fail     | 20160608 |        8 |
| 38 |     00001 | Writing         | Pass     | 20160608 |        7 |
| 39 |     00001 | Writing         | Pass     | 20160930 |       10 |
| 40 |     00001 | Social Studies  | Pass     | 20160608 |        7 |
| 41 |     00001 | Social Studies  | Pass     | 20160930 |       10 |
| 42 |     00001 | Science         | Pass     | 20160608 |        8 |
| 43 |     00001 | Reading         | Pass     | 20160608 |        2 |
| 44 |     00001 | Reading         | Pass     | 20160930 |        5 |
| 45 |     00001 | Reading         | Pass     | 20161202 |        9 |
| 46 |     00001 | Math            | Pass     | 20160608 |        8 |
+----+-----------+-----------------+----------+----------+----------+

我知道我提供了大量的额外数据,因为我只是在寻找PASS_STA为'Pass'的结果,但我想提供更多完整的图片。

基本上,出现的逻辑是,对于给定的人,当考试通过时,拉出TST_DTE和STD_SCOR列的最大值。我正在尝试使用看起来像max的多个变体,但它朝着错误的方向前进。

目前这个查询并没有给我我正在寻找的东西。

+----+-----------+-----------------+----------+----------+----------+
| id | EXAMNE_ID |    TestName     | PASS_STA | TST_DTE  | STD_SCOR |
+----+-----------+-----------------+----------+----------+----------+
| 39 |     00001 | Writing         | Pass     | 20160930 |       10 |
| 41 |     00001 | Social Studies  | Pass     | 20160930 |       10 |
| 42 |     00001 | Science         | Pass     | 20160608 |        8 |  
| 45 |     00001 | Reading         | Pass     | 20161202 |        9 |
| 46 |     00001 | Math            | Pass     | 20160608 |        8 |
+----+-----------+-----------------+----------+----------+----------+

部分我认为我需要嵌套查询,因为我正在寻找两个最大值(加上一个是日期 - 好吧,日期,因为它在varchar中),另一个是数字(但同样,存储在varchar中)或者可能以某种方式存储RANK功能?

我宁愿不必为五个主题领域中的每一个做集合CASE陈述。实际上总共有几十个主题领域,我在这里展示的这一个测试类型有五个。因此,虽然我认为汇总案例陈述可能有效,但可能过于繁琐。

有什么想法吗?

提前致谢

3 个答案:

答案 0 :(得分:1)

除数据类型问题外,您需要从您的论坛中删除std_scor,然后将having移至where

根据您的日期格式,无需将tst_dte转换为dateint,但无论如何我都包含了转化。

select 
   examne_id
 , pass_sta
 , TestName
 , max(convert(date,tst_dte)) as tst_dte
 , max(convert(int,std_scor)) as std_scor
from dbo.TestScores
group by 
   examne_id
 , pass_sta
 , TestName
having pass_sta = 'Pass'

rextester演示:http://rextester.com/BDI16678

返回:

+-----------+----------+----------------+------------+----------+
| examne_id | pass_sta |    TestName    |  tst_dte   | std_scor |
+-----------+----------+----------------+------------+----------+
|         1 | Pass     | Math           | 2016-06-08 |        8 |
|         1 | Pass     | Reading        | 2016-12-02 |        9 |
|         1 | Pass     | Science        | 2016-06-08 |        8 |
|         1 | Pass     | Social Studies | 2016-09-30 |       10 |
|         1 | Pass     | Writing        | 2016-09-30 |       10 |
+-----------+----------+----------------+------------+----------+

答案 1 :(得分:1)

;With cte(id , EXAMNE_ID ,    TestName     , PASS_STA , TST_DTE  , STD_SCOR )
AS
(
SELECT  1 , '00001' , 'Social Studies'  , 'Fail'     , '20160608',  7   Union all
SELECT  2 , '00001' , 'Science'         , 'Fail'     , '20160608',  8   Union all
SELECT  3 , '00001' , 'Reading'         , 'Fail'     , '20160608',  2   Union all
SELECT  4 , '00001' , 'Math'            , 'Fail'     , '20160608',  8   Union all
SELECT  5 , '00001' , 'Writing'         , 'Fail'     , '20160608',  7   Union all
SELECT  6 , '00001' , 'Social Studies'  , 'Fail'     , '20160608',  7   Union all
SELECT  7 , '00001' , 'Science'         , 'Fail'     , '20160608',  8   Union all
SELECT  8 , '00001' , 'Reading'         , 'Fail'     , '20160608',  2   Union all
SELECT  9 , '00001' , 'Math'            , 'Fail'     , '20160608',  8   Union all
SELECT 10 , '00001' , 'Writing'         , 'Fail'     , '20160608',  7   Union all
SELECT 11 , '00001' , 'Social Studies'  , 'Fail'     , '20160608',  7   Union all
SELECT 12 , '00001' , 'Science'         , 'Fail'     , '20160608',  8   Union all
SELECT 13 , '00001' , 'Reading'         , 'Fail'     , '20160608',  2   Union all
SELECT 14 , '00001' , 'Math'            , 'Fail'     , '20160608',  8   Union all
SELECT 15 , '00001' , 'Writing'         , 'Fail'     , '20160608',  7   Union all
SELECT 16 , '00001' , 'Social Studies'  , 'Fail'     , '20160608',  7   Union all
SELECT 17 , '00001' , 'Social Studies'  , 'Fail'     , '20160930', 10   Union all
SELECT 18 , '00001' , 'Science'         , 'Fail'     , '20160608',  8   Union all
SELECT 19 , '00001' , 'Reading'         , 'Fail'     , '20160608',  2   Union all
SELECT 20 , '00001' , 'Reading'         , 'Fail'     , '20160930',  5   Union all
SELECT 21 , '00001' , 'Math'            , 'Fail'     , '20160608',  8   Union all
SELECT 22 , '00001' , 'Writing'         , 'Fail'     , '20160608',  7   Union all
SELECT 23 , '00001' , 'Writing'         , 'Fail'     , '20160930', 10   Union all
SELECT 24 , '00001' , 'Social Studies'  , 'Fail'     , '20160608',  7   Union all
SELECT 25 , '00001' , 'Social Studies'  , 'Fail'     , '20160930', 10   Union all
SELECT 26 , '00001' , 'Science'         , 'Fail'     , '20160608',  8   Union all
SELECT 27 , '00001' , 'Reading'         , 'Fail'     , '20160608',  2   Union all
SELECT 28 , '00001' , 'Reading'         , 'Fail'     , '20160930',  5   Union all
SELECT 29 , '00001' , 'Math'            , 'Fail'     , '20160608',  8   Union all
SELECT 30 , '00001' , 'Writing'         , 'Fail'     , '20160608',  7   Union all
SELECT 31 , '00001' , 'Writing'         , 'Fail'     , '20160930', 10   Union all
SELECT 32 , '00001' , 'Social Studies'  , 'Fail'     , '20160608',  7   Union all
SELECT 33 , '00001' , 'Social Studies'  , 'Fail'     , '20160930', 10   Union all
SELECT 34 , '00001' , 'Science'         , 'Fail'     , '20160608',  8   Union all
SELECT 35 , '00001' , 'Reading'         , 'Fail'     , '20160608',  2   Union all
SELECT 36 , '00001' , 'Reading'         , 'Fail'     , '20160930',  5   Union all
SELECT 37 , '00001' , 'Math'            , 'Fail'     , '20160608',  8   Union all
SELECT 38 , '00001' , 'Writing'         , 'Pass'     , '20160608',  7   Union all
SELECT 39 , '00001' , 'Writing'         , 'Pass'     , '20160930', 10   Union all
SELECT 40 , '00001' , 'Social Studies'  , 'Pass'     , '20160608',  7   Union all
SELECT 41 , '00001' , 'Social Studies'  , 'Pass'     , '20160930', 10   Union all
SELECT 42 , '00001' , 'Science'         , 'Pass'     , '20160608',  8   Union all
SELECT 43 , '00001' , 'Reading'         , 'Pass'     , '20160608',  2   Union all
SELECT 44 , '00001' , 'Reading'         , 'Pass'     , '20160930',  5   Union all
SELECT 45 , '00001' , 'Reading'         , 'Pass'     , '20161202',  9  Union all
SELECT 46 , '00001' , 'Math'            , 'Pass'     , '20160608',  8 
)
SELECT id
    ,EXAMNE_ID
    ,TestName
    ,PASS_STA
    ,TST_DTE
    ,STD_SCOR
FROM (
    SELECT *
        ,ROW_NUMBER() OVER (
            PARTITION BY TestName ORDER BY id DESC
            ) AS Rno
    FROM (
        SELECT *
            ,ROW_NUMBER() OVER (
                PARTITION BY TestName
                ,TST_DTE ORDER BY id DESC
                ) AS Seq
        FROM cte
        ) Dt
    WHERE Dt.Seq = 1
        AND PASS_STA = 'Pass'
    ) dt2
WHERE dt2.Rno = 1
ORDER BY dt2.id ASC

输出

+----+-----------+-----------------+----------+----------+----------+
| id | EXAMNE_ID |    TestName     | PASS_STA | TST_DTE  | STD_SCOR |
+----+-----------+-----------------+----------+----------+----------+
| 39 |     00001 | Writing         | Pass     | 20160930 |       10 |
| 41 |     00001 | Social Studies  | Pass     | 20160930 |       10 |
| 42 |     00001 | Science         | Pass     | 20160608 |        8 |  
| 45 |     00001 | Reading         | Pass     | 20161202 |        9 |
| 46 |     00001 | Math            | Pass     | 20160608 |        8 |
+----+-----------+-----------------+----------+----------+----------+

答案 2 :(得分:0)

对每位学生的记录进行排名,并按日期与ROW_NUMBER进行测试。然后只记录每个学生的最新日期和考试(即排名第一的记录)。

select examne_id, pass_sta, testname, tst_dte, std_scor
from
(
  select 
    ts.*, 
    row_number() over (partition by examne_id, testname order by tst_dte desc) as rn
  from dbo.testscores ts
  where pass_sta = 'Pass'
)
where rn = 1;