T-SQL:基于 MAX 选择列(其他列)

Posted

技术标签:

【中文标题】T-SQL:基于 MAX 选择列(其他列)【英文标题】:T-SQL: Selecting Column Based on MAX(Other Column) 【发布时间】:2011-04-10 11:08:23 【问题描述】:

我希望有一种不使用子查询的简单方法:

场景:您有“TableA”,其中包含“Key”、“SubKey”和“Value”列。我需要获取给定“键”的 MAX(“子键”) 的“值”。

所以如果表格包含行:

KEY SUBKEY VALUE
1   1      100
1   2      200
1   3      300

对于 Key = 1,我需要值 300。我希望这样做:

SELECT
  VALUE
FROM
  TableA
WHERE
  Key = 1
HAVING
  SubKey = MAX(SubKey)

但这是不行的。有没有办法在不执行“WHERE SubKey = (subselect for max subkey)”的情况下做到这一点?

【问题讨论】:

【参考方案1】:

很简单,不用join,不用子查询:

SELECT FIRST_VALUE(Value) OVER (ORDER BY SubKey DESC)
FROM TableA
WHERE Key = 1

如果您需要每个键的最大值:

SELECT DISTINCT Key, 
FIRST_VALUE(Value) OVER (PARTITION BY Key ORDER BY SubKey DESC)
FROM TableA

【讨论】:

【参考方案2】:

OMG Ponie 的 ROW_NUMBER 方法是在所有情况下都最有效的方法,因为如果有两个相同数量的 MAX 值返回比预期更多的记录并破坏可能的记录,它不会失败插入你可能已经被那个recordset喂饱了。

缺少的一件事是如何在必须返回与每个最大值关联的子键的情况下执行此操作,同时也有多个键。只需将summaryMINGROUP“本身”一起加入您的表即可。

WITH summary AS (
  SELECT t.*,
         ROW_NUMBER() OVER(ORDER BY t.subkey DESC) AS rank
    FROM TABLE t
   WHERE t.key = 1)
SELECT s.*
  FROM summary s
  join  (select key, min(rank) as rank
        from summary
        group by key) sMAX
        on s.key = sMAX.key and r.rank = sMAX.rank

【讨论】:

【参考方案3】:

如果有多个键使用 CTE:

WITH CTE AS
(
    SELECT key1, key2, MAX(subkey) AS MaxSubkey
    FROM TableA 
    GROUP BY key1, key2
)
SELECT a.Key1, a.Key2, a.Value
FROM TableA a
    INNER JOIN CTE ON a.key1 = CTE.key1 AND a.key2 = CTE.key2 AND
                      a.subkey = CTE.MaxSubkey

【讨论】:

【参考方案4】:

如果您总是只希望一个键值的一行而不是多个键的答案,那么所有连接的东西都是无用的过度构建。只需使用 OMG Ponies 已经为您提供的 TOP 1 查询。

【讨论】:

【参考方案5】:

使用自联接:

这将返回所有子键值匹配的值,以防有多个。

SELECT a.value
  FROM TABLE a
  JOIN (SELECT MAX(t.subkey) AS max_subkey
          FROM TABLE t
         WHERE t.key = 1) b ON b.max_subkey = a.subkey
 WHERE a.key = 1

使用 RANK 和 CTE (SQL Server 2005+):

这将返回所有子键值匹配的值,以防有多个。

WITH summary AS (
  SELECT t.*,
         RANK() OVER(ORDER BY t.subkey DESC) AS rank
    FROM TABLE t
   WHERE t.key = 1)
SELECT s.value
  FROM summary s
 WHERE s.rank = 1

使用 ROW_NUMBER 和 CTE (SQL Server 2005+):

这将返回一行,即使有多个具有相同的子键值...

WITH summary AS (
  SELECT t.*,
         ROW_NUMBER() OVER(ORDER BY t.subkey DESC) AS rank
    FROM TABLE t
   WHERE t.key = 1)
SELECT s.value
  FROM summary s
 WHERE s.rank = 1

使用 TOP:

这将返回一行,即使有多个具有相同的子键值...

  SELECT TOP 1
         t.value
    FROM TABLE t
   WHERE t.key = 1
ORDER BY t.subkey DESC

【讨论】:

由于实际查询是几个表链接在一起,我最终选择了“选择前 1 个,有序 desc”方法,因为这似乎是最容易阅读的 @John:这很好,但是如果您需要处理每个键的最高值,那么分析版本(RANK、ROW_NUMBER)更适合。 如果您使用的是 SQL Server 2012 或更高版本,请参阅以下来自 @Nguyen 的答案。 ***.com/a/35477271/269123【参考方案6】:

OMG Ponies 采用了大多数方式来做到这一点。还有一个:

SELECT
    T1.value
FROM
    My_Table T1
LEFT OUTER JOIN My_Table T2 ON
    T2.key = T1.key AND
    T2.subkey > T1.subkey
WHERE
    T2.key IS NULL

T2.key 为 NULL 的唯一时间是 LEFT JOIN 中没有匹配项,这意味着不存在具有更高子键的行。如果多行具有相同(最高)的子键,这将返回多行。

【讨论】:

这非常适合为每个键拉出一行。【参考方案7】:
SELECT MAX(Value)
FROM TableA t1
GROUP BY Key, SubKey
HAVING SubKey = (SELECT MAX(SubKey) FROM TableA t2 WHERE t1.Key = t2.Key)
  AND Key = 1

【讨论】:

以上是关于T-SQL:基于 MAX 选择列(其他列)的主要内容,如果未能解决你的问题,请参考以下文章

T-SQL基于分隔符拆分列并将拆分后的字符串数组输入到多个表列中

基于 MySQL 中其他列的查询条件列

在 LibreOffice 或其他电子表格工具中应用基于行的过滤器而不是基于列的过滤器

SQL 从同一个表(实际上是同一列)中选择两行,基于与其他表的连接

使用 dplyr contains() 基于多个字符串选择列

如何在 T-SQL 中将列与旋转其他列相加