2009-12-30 151 views
1

我需要获取最大值和最小值,但也需要在同一行获取这些最大值或最小值的行ID。SQL查询最小最大值

SELECT MIN([Value]), MAX([Value]), id 
FROM [AnalystEstimates].[dbo].[AnalystEstimateValues] 
GROUP BY indicatorid 
+0

是否需要ID和MIN,然后是ID和Max。在2行?彼此相邻? – 2009-12-30 08:16:57

+0

是的,它会很酷,如果ID和MIN,然后ID和Max ar彼此相邻 – Woland 2009-12-30 08:20:36

+2

@Woland:您是否介意编辑您的问题以反映更改的要求? – 2009-12-30 08:23:08

回答

3

这是很不清楚你想从你的问题。你真的想要GROUP BY indicatorid吗?如果不是那么这很简单,你已经有很多答案。但是,如果你确实想要GROUP BY,那就更困难了,没有人知道它是否正确。我还假设你只需要每个indicatorid一行,并且如果有重复的行具有相同的最大/最小值,那么最好是任意选择其中一个,而不是返回两个行。

这里是我的尝试,使用CTE(需要SQL Server 2005或更新版本):

WITH 
    RowNumbers AS (
     SELECT ROW_NUMBER() OVER (ORDER BY indicatorid, value) AS RowNumber, * 
     FROM [AnalystEstimates].[dbo].[AnalystEstimateValues]), 
    MinRowNumbers AS (
     SELECT indicatorid, MIN(RowNumber) AS RowNumber FROM RowNumbers GROUP BY indicatorid), 
    MaxRowNumbers AS (
     SELECT indicatorid, MAX(RowNumber) AS RowNumber FROM RowNumbers GROUP BY indicatorid) 
SELECT 
    MinRowNumbers.indicatorid, 
    RN1.Value AS MinValue, 
    RN1.ID AS MinValueId, 
    RN2.Value AS MaxValue, 
    RN2.ID AS MaxValueId 
FROM MinRowNumbers 
JOIN MaxRowNumbers ON MinRowNumbers.indicatorid = MaxRowNumbers.indicatorid 
JOIN RowNumbers RN1 ON MinRowNumbers.RowNumber = RN1.RowNumber 
JOIN RowNumbers RN2 ON MaxRowNumbers.RowNumber = RN2.RowNumber 

这里是我用来测试它的一些数据:

CREATE TABLE AnalystEstimateValues (ID int, indicatorid int, Value int); 

INSERT INTO AnalystEstimateValues (ID, indicatorid , Value) VALUES 
(1, 1, 4), 
(2, 1, 4), 
(3, 2, 6), 
(4, 1, 2), 
(5, 2, 2), 
(6, 2, 5), 
(7, 3, 0); 

而这里的输出我得到:

indicatorid MinValue MinValueId MaxValue MaxValueId 
      1  2   4  4   2 
      2  2   5  6   3 
      3  0   7  0   7 

如果这不是你想要的,你可以请尝试改善你的问题,告诉我们你想做什么?


更新:这是基于克雷格年轻的答案的替代解决方案,但使用联接,而不是子查询:

WITH 
    UniqueIds AS (
     SELECT IndicatorId, Value, MIN(id) AS Id 
     FROM AnalystEstimateValues 
     GROUP BY IndicatorId, Value) 
SELECT 
    lims.IndicatorId, 
    MinValue, 
    T1.Id AS MinValueId, 
    MaxValue, 
    T2.Id AS MaxValueId 
FROM (
     SELECT 
      IndicatorId, 
      MIN(Value) as MinValue, 
      MAX(Value) as MaxValue 
     FROM AnalystEstimateValues 
     GROUP BY IndicatorId) lims 
JOIN UniqueIds T1 ON lims.IndicatorId = T1.IndicatorId AND lims.MinValue = T1.Value 
JOIN UniqueIds T2 ON lims.IndicatorId = T2.IndicatorId AND lims.MaxValue = T2.Value 

这是更清洁,也可能快于我的第一个版本,虽然我没有运行性能测试来验证这一点。

+0

谢谢 那就是它 – Woland 2009-12-30 09:30:05

+0

好吧,我很幸运。 :)我想下次你应该花更多时间在你的问题上,以便反应更符合你的想法。事实上,我认为这不是解决这个问题的最好方法 - 它可能太慢了。我看到你已经接受了它,但是我希望你已经证实,在你这样做之前,它对于你的数据来说足够快。如果稍后有人能够以更好的方式解决这个问题,那么他们可以看到你想要的东西,那么你应该接受他们的答案而不是这个答案。 – 2009-12-30 09:34:21

+0

我不熟悉你使用的语法;我必须阅读它。作为性能说明,您有2个GROUP BY子查询 - 一个用于MIN,另一个用于MAX。您应该能够将这些结合到一个子查询中并获得显着的性能改进。 – 2009-12-31 08:29:36

0

当您按照ID进行分组时,您的查询会返回每个ID的最大/最小值。尝试这样的事情

SELECT tblFoo.ID, tblFoo.Value 
FROM tblFoo 
WHERE (((tblFoo.Value)=(SELECT MAX([tblFoo]![Value]) FROM tblFoo))) 
    OR (((tblFoo.Value)=(SELECT MIN([tblFoo]![Value]) FROM tblFoo))); 
+1

您也失去了分组结构。 – 2009-12-30 08:35:06

0
SELECT TOP 1 
    ID, 
    'min' as type, 
    value 
FROM 
    AnalystEstimateValues 
WHERE 
    value = (select min(value) from AnalystEstimateValues) 
UNION 
    SELECT TOP 1 
    ID, 
    'max' as type, 
    value 
FROM 
    AnalystEstimateValues 
WHERE 
    value = (select max(value) from AnalystEstimateValues) 
+1

您也失去了分组结构。 – 2009-12-30 08:36:10

1

当Min = Max中,你会一开始同样的ID(也有可能被捆绑最小值和最大值)

如果不是,有/有ID(S )最小值/最大值。

基本上,您可以有2行或4列。

SELECT 
    Mn.ID, foo.MinVal, 
    Mx.ID, foo.MaxVal  
FROM 
    (
    SELECT 
     MIN([Value]) AS MinVal, 
     MAX([Value]) AS MaxVal, 
     indicatorid 
    FROM 
     [AnalystEstimates].[dbo].[AnalystEstimateValues] 
    GROUP BY 
     indicatorid 
    ) foo 
    JOIN 
    [AnalystEstimates].[dbo].[AnalystEstimateValues] Mn ON 
      foo.MinVal = Mn.[Value] AND foo.indicatorid = Mn.indicatorid 
    JOIN 
    [AnalystEstimates].[dbo].[AnalystEstimateValues] Mx ON 
      foo.MaxVal = Mx.[Value] AND foo.indicatorid = Mx.indicatorid 

编辑:

的最佳方案不会给你,你已经绑MIN行/ MAX值,除非有了这个可以做它关系

+0

ON foo.MinVal = Mn。[Value] and ON foo.MaxVal = Mx [Value] 是不可能的,因为可能有重复的值 – Woland 2009-12-30 09:24:16

+0

所以:如果有重复项,你想要哪个ID?你会如何决定一个ID比另一个ID? – gbn 2009-12-30 09:26:39

+0

如果您希望允许像这样返回多个结果,则应该在联接中包含indicatorid,否则您可以从错误的组中获取行。即你需要这个:'ON foo.MinVal = Mn。[Value] AND foo.indicatorid = Mn.indicatorid'。 – 2009-12-30 09:49:14

0

定义,虽然我没有MSSQL所以我无法测试它。特别是方括号可能需要调整。除此之外,它应该是相当标准的SQL,并做你想要的。

它获取由indicatorid分组的所有min(id/value)和max(id/value)。 在同一行。

SELECT mint.indicatorid, mint.min_id, mint.min_value, maxt.max_id, maxt.max_value 
FROM (
    SELECT indicatorid, id as min_id, MIN([Value]) AS min_value 
    FROM [AnalystEstimates].[dbo].[AnalystEstimateValues] 
    HAVING [Value] = min_value 
    GROUP BY indicatorid 
) mint JOIN (
    SELECT indicatorid, id as max_id, MAX([Value]) AS max_value 
    FROM [AnalystEstimates].[dbo].[AnalystEstimateValues] 
    HAVING [Value] = max_value 
    GROUP BY indicatorid 
) maxt ON mint.indicatorid = maxt.indicatorid 
+1

我收到此错误“ID”在选择列表中无效,因为它不包含在聚合函数或GROUP BY子句中。“ – Woland 2009-12-30 09:13:40

1

重要的问题
马克·拜尔斯样本数据表明,你需要考虑一个场景:

  • IndicatorId = 1有4
  • 一个最大值有两种标识的共享相同的最大值(1 & 2)。

那么应该显示两个id中的哪一个?

我假定它足以显示最低的ID。以下查询应该是最有效的,并且可以从(indicatorid,Value)上的索引中受益。

SELECT lims.*, 
     (
     SELECT MIN(id) 
     FROM AnalystEstimateValues m 
     WHERE m.IndicatorId = lims.IndicatorId 
      AND m.Value = lims.MinValue 
     ) AS MinId, 
     (
     SELECT MIN(id) 
     FROM AnalystEstimateValues m 
     WHERE m.IndicatorId = lims.IndicatorId 
      AND m.Value = lims.MaxValue 
     ) AS MaxId 
FROM (
     SELECT IndicatorId, 
       MIN(Value) as MinValue, 
       MAX(Value) as MaxValue 
     FROM AnalystEstimateValues 
     GROUP BY IndicatorId 
     ) lims 
+0

根据我的示例测试数据生成正确的结果。它使用相关子查询,所以我不确定它会一直很快 - 如果有非常多的非常小的指示符组,我怀疑它会变慢。但是,如果不尝试使用更真实的数据,就很难猜测这些东西。我仍然觉得必须有更好的方式来做到这一点,但无论如何+1。 – 2009-12-31 13:47:16

+0

我已经对您的解决方案进行了修改,并将其附加到我的第一个答案的末尾。我基本上做同样的事情,但使用联接而不是相关子选择。我*猜测*这会更快,但需要进行适当的测试才能确定。我不打算这么做 - 创建逼真的测试数据太费力了 - 但如果其他人这样做(Woland?),我会非常有兴趣知道结果。 – 2009-12-31 14:06:14

+0

PS:我猜你的解决方案很好,因为可能并不是那么多的指标。 – 2009-12-31 15:32:08