web-dev-qa-db-fra.com

Utilisation d'une instruction SELECT dans une clause WHERE

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)

9
jofitz

Cela s'appelle une sous-requête corrélée. Il a ses utilisations.

6
Mladen Prajdic

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.

7
Pablo Santa Cruz

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).

3
Winston Smith

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.

2
rael_kid

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

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

1
dr.Crow

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é.

0
Shamim Hafiz