it-swarm.com.de

T-SQL: Auswählen einer Spalte basierend auf MAX (andere Spalte)

Ich hoffe, es gibt einen einfachen Weg, dies ohne eine Unterabfrage zu tun:

Szenario: Sie haben "TableA" mit den Spalten "Key", "SubKey" und "Value". Ich muss den "Wert" des MAX ("SubKey") für einen bestimmten "Schlüssel" ermitteln.

Wenn also die Tabelle die Zeilen enthält:

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

Für Key = 1 brauche ich den Wert 300. Ich hatte gehofft, so etwas zu tun:

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

Aber das ist ein No-Go. Gibt es eine Möglichkeit, dies ohne "WHERE SubKey = (Subselect für Max Subkey)" zu tun?

24
John

Verwenden eines Self-Joins:

Dadurch werden alle Werte mit übereinstimmenden Unterschlüsselwerten zurückgegeben, falls Mehrfache vorhanden sind.

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

Verwenden von RANK & CTE (SQL Server 2005+):

Dadurch werden alle Werte mit übereinstimmenden Unterschlüsselwerten zurückgegeben, falls Mehrfache vorhanden sind.

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

Verwenden von ROW_NUMBER & CTE (SQL Server 2005+):

Dadurch wird eine Zeile zurückgegeben, auch wenn es mehr als eine Zeile mit demselben Unterschlüsselwert gibt.

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

Mit TOP:

Dadurch wird eine Zeile zurückgegeben, auch wenn es mehr als eine Zeile mit demselben Unterschlüsselwert gibt.

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

Sehr einfach, kein Join, keine Unterabfrage:

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

Wenn Sie einen maximalen Wert für jeden Schlüssel benötigen: 

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

OMG Ponys haben die meisten Möglichkeiten, dies zu tun. Hier ist noch eins:

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

Die einzige Zeit, zu der T2.key NULL ist, ist, wenn im LEFT JOIN keine Übereinstimmung vorhanden ist. Dies bedeutet, dass keine Zeile mit einem höheren Unterschlüssel existiert. Dies gibt mehrere Zeilen zurück, wenn mehrere Zeilen mit demselben (höchsten) Unterschlüssel vorhanden sind.

3
Tom H

Die ROW_NUMBER-Methode von OMG Ponie ist am besten für alle Szenarien geeignet, da sie nicht ausfällt, wenn zwei MAX-Werte mit derselben Menge mehr Datensätze zurückgeben als erwartet und ein eventuell vorhandenes Insert beschädigt wird von dieser recordset gespeist werden.

Was fehlt, ist die Vorgehensweise, wenn der zu jedem max-Wert gehörende Unterschlüssel zurückgegeben werden muss, wenn auch mehrere Schlüssel vorhanden sind. Verbinden Sie Ihre summary-Tabelle einfach mit einer MIN und GROUP "selbst" und los geht's. 

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

Im Falle einer GROUP BY-Abfrage können Sie den Wert einer Spalte basierend auf dem MAX-Wert einer anderen abrufen:

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

Wenn Sie immer nur eine Zeile für einen Schlüsselwert benötigen und nicht die Antwort für viele Schlüssel gleichzeitig, ist der gesamte Join-Vorgang nutzlos. Verwenden Sie einfach die TOP 1-Abfrage, die OMG Ponys Ihnen bereits gegeben hat.

0
ErikE

Bei mehreren Schlüsseln, die einen CTE verwenden:

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