SQL查询最小值最大值

时间:2009-12-30 08:13:45

标签: sql sql-server aggregate

我需要获取最大值和最小值,但我还需要在同一行上获得这些最大值或最小值的行ID。

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

6 个答案:

答案 0 :(得分:3)

目前还不清楚你的问题是什么。你真的想要GROUP BY indicatorid吗?如果没有,那么它很简单,你已经有很多答案。但是如果你确实想要GROUP BY那么它就更难了,而且没有人能够把它弄得很好。我还假设你只需要每个indicatorid一行,如果有重复的行具有相同的max / min,那么最好只选择其中一行而不是返回两者。

这是我尝试使用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

如果这不是您想要的,请您尝试改进您的问题,告诉我们您的需求吗?


更新:这是基于Craig Young答案的替代解决方案,但使用连接而不是子选择:

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

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

答案 1 :(得分:1)

如果Min = Max,您将获得相同的ID(可能存在最小值和最大值绑定)

如果没有,则每个最小/最大值都有ID

基本上你可以有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

编辑:

除非定义为WITH TIES

,否则TOP解决方案不会为您提供已绑定MIN / MAX值的行

答案 2 :(得分:1)

重要问题
Mark Byers的样本数据显示了您需要考虑的场景:

  • IndicatorId = 1的最大值为4.
  • 有两个Id共享相同的最大值(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

答案 3 :(得分: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)));

答案 4 :(得分: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)

答案 5 :(得分: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