Si positif, additionnez tous les éléments. Si négatif, retournez chacun

28

J'ai besoin de trouver un moyen d'accéder à SUM()toutes les valeurs positives numet de renvoyer SUM()tous les nombres positifs et une ligne individuelle pour chaque nombre négatif. Voici un exemple de DDL:

Create Table #Be
(
    id int
    , salesid int
    , num decimal(16,4)
)

Insert Into #BE Values
    (1, 1, 12.32), (2, 1, -13.00), (3, 1, 14.00)
    , (4, 2, 12.12), (5, 2, 14.00), (6, 2, 21.23)
    , (7, 3, -12.32), (8,3, -43.23), (9, 3, -2.32)

Et voici ma sortie souhaitée (des nombres positifs pour chaque salesid SUM()et négatifs obtiennent une ligne individuelle):

salesid    num
1          26.32
1          -13.00
2          47.35
3          -12.32
3          -43.23
3          -2.32
user2676140
la source

Réponses:

26

Essaye ça:

SELECT   salesid, sum(num) as num
FROM     #BE
WHERE    num > 0
GROUP BY salesid
UNION ALL
SELECT   salesid, num
FROM     #BE
WHERE    num < 0;

Si vous voulez les deux sumvaleurs sur une ligne, vous devez créer une fonction maxValue(et minValue) et l'utiliser comme sum(maxValue(0, num))et sum(minValue(0, num)). Ceci est décrit dans: Existe - t-il une fonction Max dans SQL Server qui prend deux valeurs comme Math.Max ​​dans .NET?

Marco
la source
8
J'ai corrigé la requête. Nécessaire UNION ALLaussi, non UNION.
ypercubeᵀᴹ
24

Cela fonctionne aussi:

SELECT salesid, SUM(num)
FROM #BE
GROUP BY salesid, CASE WHEN num >= 0 THEN 0 ELSE id END;

Hypothèses:

  • Id commence à 1, donc il peut utiliser THEN 0. salesid ELSE salesid+id+1fonctionnerait aussi
  • 0 est considéré comme un nombre positif, d'où le >= 0( Est-ce que zéro est positif ou négatif? ). Bien que cela x+0=xsemble rendre le =signe inutile, il permet de se rappeler que ce cas n'a pas été oublié et comment le 0 est traité (en tant que SUM ou en tant que ligne individuelle). Si the SUM() of all positive numberssignifie SUM of strictly positive numbers(c'est-à-dire> 0), alors =n'est pas nécessaire.

Il doit être testé avec des données et des index réels, mais avec un seul scan de table, les performances peuvent être un peu meilleures dans certains cas.

L'absence d'index semble avoir un impact moindre avec cette requête sur les données de test ci-dessous:

SET NO COUNT ON
Create Table #Be(
  id int identity(0,1)
  ,salesid int,num decimal(16,4)
)
INSERT INTO #BE(salesid, num) 
SELECT CAST(rand()*10 as int), rand() - rand()
GO 10000 -- or 100.000
Julien Vavasseur
la source
Vous pouvez simplifier votre clause de groupe avec un iif comme ceci: GROUP BY salesid, iif(num >= 0, 0, id) Cool query.
user2023861
1
Oui, mais OP devrait d'abord installer SQL Server 2012. IIF démarre avec SQL Server 2012: msdn.microsoft.com/en-us/library/hh213574.aspx . OP a tagué sa question avec SQL Server 2008.
Julien Vavasseur