SELECT * FROM ScoresTable WHERE Score =
(SELECT MAX(Score) FROM ScoresTable AS st WHERE st.Date = ScoresTable.Date)
Existe-t-il un nom pour décrire l'utilisation d'une instruction SELECT dans une clause WHERE? Est-ce une bonne/mauvaise pratique?
Serait-ce une meilleure alternative?
SELECT ScoresTable.*
FROM ScoresTable INNER JOIN
(SELECT Date, MAX(Score) AS MaxScore
FROM ScoresTable GROUP BY Date) SubQuery
ON ScoresTable.Date = SubQuery.Date
AND ScoresTable.Score = SubQuery.MaxScore
Il est beaucoup moins élégant, mais semble fonctionner plus rapidement que ma version précédente. Je ne l'aime pas car il n'est pas affiché très clairement dans l'interface graphique (et il doit être compris par les débutants SQL). Je pourrais le diviser en deux requêtes distinctes, mais les choses commencent à devenir encombrées ...
N.B. J'ai besoin de plus que de la date et du score (par exemple, le nom)
Cela s'appelle une sous-requête corrélée. Il a ses utilisations.
Ce n'est pas du tout une mauvaise pratique. Ils sont généralement appelés SOUS-REQUÊTE , SOUS-SÉLECTION ou Requête imbriquée.
C'est une opération relativement coûteuse, mais il est assez fréquent de rencontrer beaucoup de sous-requêtes lors du traitement des bases de données car c'est la seule façon d'effectuer certains types d'opérations sur les données.
Il existe une bien meilleure façon d'obtenir le résultat souhaité, en utilisant les fonctions analytiques (ou fenêtrées) de SQL Server .
SELECT DISTINCT Date, MAX(Score) OVER(PARTITION BY Date) FROM ScoresTable
Si vous avez besoin de plus que des combinaisons de date et de score maximum, vous pouvez utiliser des fonctions de classement, par exemple:
SELECT *
FROM ScoresTable t
JOIN (
SELECT
ScoreId,
ROW_NUMBER() OVER (PARTITION BY Date ORDER BY Score DESC) AS [Rank]
FROM ScoresTable
) window ON window.ScoreId = p.ScoreId AND window.[Rank] = 1
Vous pouvez utiliser RANK () au lieu de ROW_NUMBER () si vous souhaitez que plusieurs enregistrements soient retournés s'ils partagent tous les deux le même MAX (Score).
Le principe des sous-requêtes n'est pas du tout mauvais, mais je ne pense pas que vous devriez l'utiliser dans votre exemple. Si je comprends bien, vous voulez obtenir le score maximum pour chaque date. Dans ce cas, vous devez utiliser un GROUP BY.
Il s'agit d'une sous-requête corrélée.
(Il s'agit d'une requête "imbriquée" - ce terme n'est cependant pas très technique)
La requête interne prend des valeurs de la requête externe (WHERE st.Date = ScoresTable.Date), elle est donc évaluée une fois pour chaque ligne de la requête externe.
Il existe également une forme non corrélée dans laquelle la requête interne est indépendante car en tant que telle, elle n'est exécutée qu'une seule fois.
par exemple.
SELECT * FROM ScoresTable WHERE Score =
(SELECT MAX(Score) FROM Scores)
Il n'y a rien de mal à utiliser des sous-requêtes, sauf là où elles ne sont pas nécessaires :)
Votre instruction peut être réinscriptible en tant que fonction d'agrégation en fonction des colonnes dont vous avez besoin dans votre instruction select.
SELECT Max(score), Date FROM ScoresTable
Group By Date
Dans votre scénario, pourquoi ne pas utiliser la clause GROUP BY et HAVING au lieu de la table JOINING pour elle-même. Vous pouvez également utiliser d'autres fonctions utiles. voir ce lien
La sous-requête est le nom.
Parfois, cela est nécessaire, mais bon/mauvais dépend de la façon dont il est appliqué.