J'ai de la difficulté à comprendre comment fonctionne l'agrégat

Permettez-moi d'abord de vous présenter un exemple, après quoi je poserai la question. Code

SELECT orderyear ,qty FROM Sales.OrderTotalsByYear; 

me donne une table qui ressemble à ceci

 orderyear qty ----------- ----------- 2007 25489 2008 16247 2006 9581 

Je dois returnner pour chaque année l'année de la command, la quantité et la quantité totale courante au cours des années. C'est-à-dire, pour chaque année, returnner la sum de la quantité jusqu'à cette année. Ainsi, pour la première année enregistrée dans la vue (2006), le total cumulatif est égal à la quantité de cette année. Pour la deuxième année (2007), le total cumulatif est la sum de la première année et de la deuxième année, et ainsi de suite. Le code ressemble à ceci

 SELECT orderyear ,qty ,( SELECT SUM(O2.qty) FROM Sales.OrderTotalsByYear AS O2 WHERE O2.orderyear <= O1.orderyear ) AS runqty FROM Sales.OrderTotalsByYear AS O1 ORDER BY orderyear; 

et une table

 orderyear qty runqty ----------- ----------- ----------- 2006 9581 9581 2007 25489 35070 2008 16247 51317 

Maintenant, je comprends ce que fait ce code mais je ne comprends pas COMMENT il le fait. J'ai de l'expérience en programmation procédurale et orientée object mais cela me rend fou. Si la requête va dans un sens comme celui-ci

  1. DE
  2. PAR GROUPE
  3. AYANT
  4. SÉLECTIONNER
  5. COMMANDÉ PAR

alors comment il parvient à combiner intérieur SELECT intérieur externe SELECT en utilisant des relations entre interne et externe SELECT? Le SELECT externe est-il exécuté en premier et s'arrête-t-il lorsqu'il frappe le premier élément à l'intérieur d'une table, puis le SELECT interne commence à s'exécuter pour les éléments où O2.orderyear <= O1.orderyear est vrai? Ou y a-t-il quelque chose de totalement différent?

Logiquement , pour chaque ligne générée par le système (via FROM , WHERE , GROUP BY et HAVING ), le système évaluera la clause SELECT . Dans le cadre de cette évaluation de chaque ligne, le système évaluera la sous-requête corrélée:

 ( SELECT SUM(O2.qty) FROM Sales.OrderTotalsByYear AS O2 WHERE O2.orderyear <= O1.orderyear ) 

Utilisation de la valeur O1.orderyear la ligne actuelle.

Cependant, d'un sharepoint vue pratique 1 , le système peut être en mesure d'optimiser son évaluation de cette sous-requête. Un optimiseur assez intelligent, si les statistics suggèrent qu'il vaut la peine de le faire, peut décider d'évaluer la requête externe dans l'ordre orderyear , et de créer également une copy de la table OrderTotalsByYear sortingée dans l'ordre orderyear (ou d'utiliser un index qui représente déjà cet ordre de sorting). Dans un tel cas, le système serait en mesure d'évaluer ce résultat de la sous-requête sans avoir à re-scanner la table entière OrderTotalsByYear pour chaque ligne de la requête externe.

Ce que fait l'optimiseur ne peut être déterminé qu'en obtenant le plan d'exécution, et dépendra de vos tables spécifiques – leur structure, leurs index et datatables qu'ils contiennent.


1 SQL est défini en termes d'ordre de traitement logique . Les implémentations sont libres d'effectuer des opérations dans un ordre différent de celui de l'ordre de traitement logique, à condition qu'elles produisent les mêmes résultats qui auraient été obtenus si l'ordre de traitement logique était suivi 2 . SQL est généralement défini pour travailler sur des sets plutôt que pour spécifier un traitement ligne par ligne ou de gauche à droite.

2 SQL Server prend plus de libertés qu'il ne le devrait et peut générer des erreurs qui n'auraient pas été générées s'il avait suivi l'ordre de traitement logique. Ho hum.

Vous pouvez penser à la requête en deux étapes: La sous-requête de votre clause select est corrélée, c'est-à-dire qu'elle fait reference à la requête principale via O2.orderyear <= O1.orderyear . La requête principale est donc exécutée, et pour chaque logging lu dans la table (alias O1), elle exécute la sous-requête afin d'get la quantité courante.

Ainsi, lorsque la requête principale lit l'logging pour 2008, elle exécute

 SELECT SUM(O2.qty) FROM Sales.OrderTotalsByYear AS O2 WHERE O2.orderyear <= 2008 

Il y a deux loggings avec une année <= 2008: 2007 et 2008. Leurs quantités sont ajoutées, et donc vous obtenez le total cumulé à afficher avec l'logging de 2008. La même chose est faite pour les records 2007 et 2009. Enfin, vos rangées sont ordonnées afin de montrer les années dans l'ordre croissant.