【问题标题】:How to get a row number or ID of where the MAX() value was found如何获取找到 MAX() 值的行号或 ID
【发布时间】:2019-06-09 12:41:20
【问题描述】:

美好的一天社区。 我很难想出一种方法来实现我试图得到的结果。由于我对 SQL 查询不太熟练,我开始失去理智。我要做的是在特定测试中找到最高和最低等级,但我也希望获得 MAX() 和 MIN() 所在行的 ID 或行号(它们匹配)是成立。

“结果”表如下所示:

 ResultID|Test_UK|Test_US|TestUK_Scr|TestUS_Scr|TestTakenOn
   1         1       3      85          14     2018-11-22 00:00:00.000
   2         3       1      41          94     2018-11-23 00:00:00.000
   3         2       4      71          54     2018-11-24 00:00:00.000
   4         4       2      51          52     2018-12-25 00:00:00.000
   5         6       3      74          69     2018-12-01 00:00:00.000
   6         3       6      83          57     2018-12-02 00:00:00.000
   7         7       4      91          98     2018-12-03 00:00:00.000
   8         4       7      88          22     2018-12-04 00:00:00.000
   9         5       8      41          76     2018-12-08 00:00:00.000
   10        8       5      37          64     2018-12-09 00:00:00.000

我运行查询时得到的结果...

TestID|TopScore|LowScore|LastDateTestTaken
   1      94       85    2018-11-23 00:00:00.000
   2      71       52    2018-11-25 00:00:00.000
   3      83       14    2018-12-02 00:00:00.000
   4      98       51    2018-12-04 00:00:00.000
   5      64       41    2018-12-09 00:00:00.000
   6      74       57    2018-12-02 00:00:00.000
   7      91       22    2018-12-04 00:00:00.000
   8      76       37    2018-12-09 00:00:00.000

这是我正在处理的查询。

这个查询返回上面提到的结果

WITH
-- Combine the results of UK and US tests
    Combined_Results_Both_Tests AS(
                select ResultID as resultID, Test_UK as TestID, Test_UK_Scr as TestScore, TestTakenOn as TestDate from Results
                union all 
                select ResultID as resultID, Test_US as TestID, Test_US_Scr as TestScore, TestTakenOn as TestDate from Results),
--Gets TOP and WORST results of the tests, LastDateTaken (Needs to add ResultID!)
    Get_Best_and_Worst_Results_And_LastTestDate AS(
                SELECT TestID ,max(TestScore) AS TopScore ,min(TestScore) AS LowScore ,max(TestDate) AS LastDateTestTaken
                FROM Combined_Results_Both_Tests
                GROUP BY TestID)
--Final query execution
SELECT * FROM Get_Best_and_Worst_Results_And_LastTestDate

我试图用这样的方法来达到我想要的结果,但它不起作用而且效率也很低。我的意思是它不起作用,每当在美国和英国的测试中发现匹配时,它就会充满重复。

--Gets ReslutID of Min and Max values
    Get_ResultID_Of_Results AS(
                SELECT * FROM Get_Best_and_Worst_Results_And_LastTestDate A
                CROSS APPLY
                (SELECT ResultID FROM Results res
                WHERE   (A.TestID = res.Test_UK AND A.TopScore = res.Test_UK_Scr) OR
                        (A.TestID = res.Test_US AND A.TopScore = res.Test_UK_Scr) OR
                        (A.TestID = res.Test_UK AND A.LowScore = res.Test_UK_Scr) OR
                        (A.TestID = res.Test_US AND A.LowScore = res.Test_UK_Scr) OR
                        (A.TestID = res.Test_UK AND A.TopScore = res.Test_US_Scr) OR
                        (A.TestID = res.Test_US AND A.TopScore = res.Test_US_Scr) OR
                        (A.TestID = res.Test_UK AND A.LowScore = res.Test_US_Scr) OR
                        (A.TestID = res.Test_US AND A.LowScore = res.Test_US_Scr)) D)
SELECT * FROM Get_ResultID_Of_Results

这是我试图达到的结果(额外的列将说明最大值和最小值的找到位置)将说明结果表中的 ResultID。此外,行号与表中的 ResultID 匹配。

TestID|TopScore|LowScore|LastDateTestTaken    |MaxValueLocID|MinValueLocID|
   1      94       85    2018-11-23 00:00:00.000       2             1
   2      71       52    2018-11-25 00:00:00.000       3             4
   3      83       14    2018-12-02 00:00:00.000       6             1
   4      98       51    2018-12-04 00:00:00.000       7             4
   5      64       41    2018-12-09 00:00:00.000       10            9
   6      74       57    2018-12-02 00:00:00.000       5             6
   7      91       22    2018-12-04 00:00:00.000       7             8
   8      76       37    2018-12-09 00:00:00.000       9             10

寻求有关解决方案的任何帮助,无论是理论上的还是实际的。谢谢!

【问题讨论】:

  • 它看起来不像 Max(), Min() 的东西,例如在第一个示例中,对于 Id = 1,最高是 94,最低是 85(无论如何,该 ID 来自哪里)?
  • @CetinBasoz 如果您查看结果表,您可以看到 Test_UK 和 Test_US 有 ID。它们都代表在两个不同国家/地区进行的测试(相同的测试因此 ID),我想要做的是找到测试的最高和最低分数。因此,ID 为 1 的英国测试中的结果第 1 行和第 2 行得到了 85,而在美国(结果的第 2 行)它得到了 94,因此最大 94 和最低 85。
  • 但是对于第一行最高和最低不是 94、85 而是 94 和 14。所以它不止于此。不是最大,最小,而是美国 vs 英国?
  • @CetinBasoz,你可以这么说,它更多的是找到两国结合的特定测试的最高和最低分数。因此联合。

标签: sql sql-server database tsql rdbms


【解决方案1】:

如果我的操作正确,您希望取消透视数据并进行汇总:

select v.testid, max(v.score), min(v.score) max(v.TestTakenOn)
from results r cross apply
     (values (Test_UK, TestUK_Scr, TestTakenOn),
             (Test_US, TestUS_Scr, TestTakenOn)
     ) v(testid, score, TestTakenOn)
group by v.testid;

然后你可以使用窗口函数来修改它:

select v.testid, max(v.score), min(v.score) max(v.TestTakenOn),
       max(case when seqnum_desc = 1 then resultid end) as resultid_max,
       max(case when seqnum_asc = 1 then resultid end) as resultid_min
from (select r.resultid, v.*,
             row_number() over (partition by v.testid order by v.score asc) as seqnum_asc,
             row_number() over (partition by v.testid order by v.score desc) as seqnum_desc
      from results r cross apply
           (values (Test_UK, TestUK_Scr, TestTakenOn),
                   (Test_US, TestUS_Scr, TestTakenOn)
           ) v(testid, score, TestTakenOn)
     ) v
group by v.testid;

【讨论】:

  • SQL 不太好,并且还收到语法错误。无论出于何种原因,都无法绑定 v.testid。有什么特别的原因吗?
  • 抱歉,我想通了,但仍然不完全正确,因为它从行中找到最小值和最大值,而我需要根据 Test_UK 和 Test_US 和 Scr 中的 ID 找到它列,我会将您的查询生成的结果添加到原始问题中。你会明白我的意思
  • @Mr.Softy 。 . .结果应该是你现在想要的。我修正了错字。
  • 太棒了,作为参考,如果将来有人想以此作为参考,在选择 max(v.TestTakenOn) 之前还有一个错字。列名有一些不匹配,但那是次要的。很好的答案!
  • @Mr.Softy 。 . .这种方法应该比使用union allgroup byjoin 的方法更快更简洁。
【解决方案2】:
with allScores (TestId, Score, TestTakenOn, valueLoc) as
(
  select [Test_UK], [TestUK_Scr],[TestTakenOn], ResultId from scores
  union all
  select [Test_US], [TestUS_Scr],[TestTakenOn], ResultId from scores
),
maxMin (TestId, MaxScore, MinScore, LastTestDate) as (
  select TestId, Max(score), Min(score), Max(TestTakenOn)  
  from allScores
  group by TestId
)
select mm.*, a1.valueLoc as MaxValueLoc, a2.ValueLoc as MinValueLoc
from maxMin mm
inner join allScores a1 
on mm.TestId = a1.TestId and mm.MaxScore = a1.score
inner join allScores a2 
on mm.TestId = a2.TestId and mm.MinScore = a2.score;

DBFiddle demo

【讨论】:

  • @Mr.Softy,可惜你不能,试着跑吧。我忘了添加 MAxValueLoc 和 MinValueLoc。编辑添加它们。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多