使用SQL Query生成多个最大值和最小值

时间:2011-03-22 15:32:25

标签: mysql sql ms-access-2007

我对SQL的一个奇怪的限制感到沮丧 - 它显然无法将一个记录与聚合函数之外的另一个记录联系起来。这样就总结了我的问题。 我有一张桌子,已经分类了。我需要找到它的最大值(注意复数!)和最小值。不,我不是在寻找单个最大值或单个最小值。更具体地说,我正在尝试生成数字序列的局部峰值列表。生成此算法的粗略描述是:

WHILE NOT END_OF_TABLE
 IF RECORD != FIRST_RECORD AND RECORD != LAST_RECORD THEN
  IF ((RECORD(Field)<RECORD_PREVIOUS(Field) AND RECORD(Field)<RECORD_NEXT(Field)) OR
      RECORD(Field)>RECORD_PREVIOUS(Field) AND RECORD(Field)>RECORD_NEXT(Field)) THEN
     ADD_RESULT RECORD
  END IF
 END IF
END WHILE

看问题?我需要查询给定记录必须与上一个和下一个记录的值进行比较。这甚至可以在标准SQL中完成吗?

4 个答案:

答案 0 :(得分:2)

许多人都感到沮丧;虽然SQL非常适合使用通用集,但在尝试处理特定于有序集的问题时,它是非常不足的(无论它是在表中物理排序还是存在隐含或明确的逻辑顺序是无关紧要的)。有些事情可以提供帮助(例如,rank()row_number()函数),但解决方案可能因RDBMS而异。

如果您可以具体说明您正在使用哪个平台,我或其他人可以提供更详细的答案。

答案 1 :(得分:2)

你必须自我加入两次并生成一个没有间隙的rownumber:

在T-SQL中:

WITH ordered AS (
    SELECT ROW_NUMBER() OVER (ORDER BY your_sort_order) AS RowNumber
           ,* -- other columns here
)
SELECT *
FROM ordered
LEFT JOIN ordered AS prev
    ON prev.RowNumber = ordered.RowNumber - 1
LEFT JOIN ordered AS next
    ON next.RowNumber = ordered.RowNumber + 1
WHERE -- here you put in your local min/local max and end-point handling logic - end points will have NULL in next/prev

答案 2 :(得分:1)

是。您需要自联接 - 但如果没有数据库架构,则很难具体说明解决方案。

具体来说,我想知道你提到的“订购”事情 - 但我会假设我们可以使用“ID”字段。

(哦,我正在使用老式的连接语法,因为我是恐龙)。

select *
from   myTable   main,
       myTable   previous,
       myTable   next
where  previous.id  = main.id - 1
and    next.id      = main.id + 1
and    previous.record > main.record
and    next.record     < main.record

(我认为我已经在大于/小于条款中正确地解释了你的要求,但要适应品味)。

答案 3 :(得分:1)

SELECT
  current.RowID,
  current.Value,
  CASE WHEN
    (
     (current.Value < COALESCE(previous.Value,   current.Value + 1))
     AND
     (current.Value < COALESCE(subsequent.Value, current.Value + 1))
    )
  THEN
    'Minima'
  ELSE
    'Maxima'
  END
FROM
  myTable  current
LEFT JOIN
  myTable  previous
    ON previous.RowID = (SELECT MAX(RowID) FROM myTable WHERE RowID < current.ROWID)
LEFT JOIN
  myTable  subsequent
    ON subsequent.RowID = (SELECT MIN(RowID) FROM myTable WHERE RowID > current.ROWID)
WHERE
  (
   (current.Value < COALESCE(previous.Value,   current.Value + 1))
   AND
   (current.Value < COALESCE(subsequent.Value, current.Value + 1))
  )
  OR
  (
   (current.Value > COALESCE(previous.Value,   current.Value - 1))
   AND
   (current.Value > COALESCE(subsequent.Value, current.Value - 1))
  )

注意:&lt;和&gt;逻辑是从您复制的,但不适合在一个或多个连续记录中相等的局部最大值/最小值。

注意:我已经创建了一个虚构的RowID来按顺序加入记录,重要的是联接获取“上一个”和“后续”记录。

注意: LEFT JOIN和COALESCE语句会导致第一个和最后一个值始终被计为最大值或最小值。