2010-01-12 6 views
1

J'ai résolu ce problème, mais je me demande simplement pourquoi cela fonctionne comme il le fait. J'ai une table temporaire que je sélectionne et je cherche à afficher un nom, le nombre d'enregistrements qui correspondent à ce nom, et le pourcentage pour ce nom du total des enregistrements. Ceci est la façon dont j'avais l'origine il:Problème d'arrondi SQL Server Recherche d'une explication

SELECT name, number, 
CASE WHEN number = 0 THEN 0 ELSE 
convert(Numeric(10,2), number/CONVERT(decimal(5,2),SUM(number)) * 100) 
END as "Percentage of Total" 
FROM #names 
group by name, number 

Les résultats que je recevais étaient:

name      number  Percentage of Total 
------------------------- ----------- --------------------------------------- 
Test 1      0   0.00 
Test 2      22   100.00 
Test 3      28   100.00 

Lorsque je change la requête à cela, les résultats sont corrects:

declare @total decimal(5,2) 

    select @total = SUM(number) FROM #names 

    SELECT name, number, convert(Numeric(10,2), number/ @total * 100) as "Percentage of Total" 
    FROM #names 
    group by name, number 

correcte Résultats:

name      number  Percentage of Total 
------------------------- ----------- --------------------------------------- 
Test 1      22   44.00 
Test 2      0   0.00 
Test 3      28   56.00 

Quelqu'un peut-il expliquer ce qui se passe, j'aimerais mieux le comprendre. Merci!

Jon

Répondre

1

Vous devez d'abord interroger les groupes par numéro.

Comme vous n'avez pas de doublons de nombres, number/SUM(number) est équivalent au 1/COUNT (sauf lorsque le numéro est 0).

Votre seconde requête ne se regroupe pas par numéro, elle calcule la somme totale.

Utilisez ce lieu:

SELECT name, number * 100.0/SUM(number) OVER() 
FROM #names 

Lorsqu'il est utilisé avec OVER clause, SUM devient la fonction analytique plutôt que celui d'agrégat.

Il ne rétrécit pas plusieurs enregistrements en un seul: au lieu, elle retourne la valeur totale ainsi que chaque enregistrement:

-- This is an aggregate function. It shrinks all records into one record and returns the total sum 

WITH q (name, number) AS 
     (
     SELECT 'test1', 0 
     UNION ALL 
     SELECT 'test2', 22 
     UNION ALL 
     SELECT 'test3', 28 
     ) 
SELECT SUM(number) 
FROM q 

-- 
50 

-- This is an analytical function. It calcuates the total sum as well but does not shrink the records. 

WITH q (name, number) AS 
     (
     SELECT 'test1', 0 
     UNION ALL 
     SELECT 'test2', 22 
     UNION ALL 
     SELECT 'test3', 28 
     ) 
SELECT SUM(number) OVER() 
FROM q 

-- 
50 
50 
50 
+0

Wow Merci pour la réponse rapide et une grande réponse! Pouvez-vous expliquer ce que OVER() fait dans cette requête? Cela fonctionne parfaitement, je veux juste comprendre ce qui se passe. – Jon