web-dev-qa-db-fra.com

T-SQL: Sélection d'une colonne en fonction de MAX (autre colonne)

J'espère qu'il existe un moyen simple de faire cela sans utiliser une sous-requête:

Scénario: Vous avez "TableA" avec les colonnes "Key", "SubKey" et "Value". Je dois obtenir la "valeur" du MAX ("SubKey") pour une "clé" donnée.

Donc, si la table contenait les lignes:

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

Pour Key = 1, j'ai besoin de la valeur 300. J'espérais faire quelque chose comme ceci:

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

Mais c'est un non-aller. Y a-t-il un moyen de faire cela sans faire un 'WHERE SubKey = (sous-sélectionner pour max sous-clé)'?

24
John

Utiliser une auto-jointure:

Cela retournera toutes les valeurs avec des valeurs de sous-clé qui correspondent, au cas où il y aurait des multiples.

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

Utilisation de RANK & CTE (SQL Server 2005+):

Cela retournera toutes les valeurs avec des valeurs de sous-clé qui correspondent, au cas où il y aurait des multiples.

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

Utilisation de ROW_NUMBER & CTE (SQL Server 2005+):

Cela retournera une ligne, même s'il y en a plusieurs avec la même valeur de sous-clé ...

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

En utilisant TOP:

Cela retournera une ligne, même s'il y en a plusieurs avec la même valeur de sous-clé ...

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

Très simple, pas de jointure, pas de sous-requête:

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

Si vous avez besoin d'une valeur maximale pour chaque clé: 

SELECT DISTINCT Key, 
FIRST_VALUE(Value) OVER (PARTITION BY Key ORDER BY SubKey DESC)
FROM TableA
15
Nguyen Viet Cuong
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
4
Amy B

Les poneys OMG trouvent la plupart des moyens de le faire. En voici un de plus:

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

La seule fois que T2.key sera NULL est lorsqu'il n'y a pas de correspondance dans LEFT JOIN, ce qui signifie qu'aucune ligne n'existe avec une sous-clé supérieure. Cela renverra plusieurs lignes s'il y a plusieurs lignes avec la même sous-clé (la plus élevée).

3
Tom H

La méthode ROW_NUMBER de OMG Ponie est celle qui fonctionnera le mieux dans tous les scénarios car elle n’échouera pas si deux valeurs MAX avaient le même montant renvoyant plus d’enregistrements que prévu et brisaient un éventuel insert être nourri par cette recordset.

Une chose qui manque, c'est comment le faire dans le cas où il faut retourner la sous-clé associée à chaque valeur maximale, quand il y a aussi plusieurs clés. Joignez simplement votre table summary avec une MIN et GROUP "elle-même" et c'est parti. 

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
1
Diego

Dans le cas d'une requête GROUP BY, pour obtenir la valeur d'une colonne en fonction de la valeur MAX d'une autre, vous pouvez effectuer les opérations suivantes:

SELECT
        CASE 
             WHEN MAX(col_C) > 0 THEN MAX(col_D)
             ELSE NULL 
        END     AS col_D_value_when_col_C_MAX
FROM table 
GROUP BY col_A, col_B
0

Si vous voulez toujours une seule ligne pour une valeur de clé plutôt que la réponse pour plusieurs clés à la fois, tous les éléments de jointure constituent une construction inutile. Utilisez simplement la requête TOP 1 OMG Ponies que vous avez déjà donnée.

0
ErikE

En cas de clés multiples utilisant un 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
0
Glen