Se positivo, some todos os itens. Se negativo, retorne cada um

28

Estou precisando encontrar um caminho para SUM()todos os valores positivos nume retornar o SUM()número positivo de todos e uma linha individual para cada número negativo. Abaixo está uma amostra 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)

E esta é a minha saída desejada (números positivos para cada vendedor SUM()e negativos recebem uma linha individual retornada):

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

Respostas:

26

Tente o seguinte:

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

Se você deseja os dois sumvalores em uma linha, deve criar uma função maxValue(e minValue) e usá-la como sum(maxValue(0, num))e sum(minValue(0, num)). Isso está descrito em: Existe uma função Max no SQL Server que aceita dois valores como Math.Max ​​no .NET?

Marco
fonte
8
Corrigi a consulta. Necessário UNION ALLtambém, não UNION.
ypercubeᵀᴹ
24

Isso também funciona:

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

Suposições:

  • O ID começa em 1, portanto, ele pode ser usado THEN 0. salesid ELSE salesid+id+1funcionaria bem
  • 0 é considerado número positivo, daí o >= 0( é zero positivo ou negativo? ). Embora x+0=xpareça tornar o =sinal desnecessário, ajuda a lembrar que este caso não foi esquecido e como 0 é tratado (como uma SOMA ou como uma linha individual). Se the SUM() of all positive numberssignifica SUM of strictly positive numbers(ie> 0), então =não é necessário.

Ele deve ser testado com dados e índices reais, mas com apenas uma varredura de tabela, o desempenho pode ser um pouco melhor em alguns casos.

A ausência de um índice parece ter um impacto menor com esta consulta nos dados de teste abaixo:

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
fonte
Você pode simplificar sua cláusula de grupo com um iif como este: GROUP BY salesid, iif(num >= 0, 0, id) Consulta legal.
user2023861
1
Sim, mas o OP precisaria primeiro instalar o SQL Server 2012. O IIF inicia com o SQL Server 2012: msdn.microsoft.com/en-us/library/hh213574.aspx . OP marcou sua pergunta com o SQL Server 2008.
Julien Vavasseur