Jeśli pozytywne, zsumuj wszystkie pozycje. Jeśli ujemny, zwróć każdy

28

Potrzebuję znaleźć sposób na SUM()wszystkie wartości dodatnie numi zwrócić SUM()wszystkie liczby dodatnie i pojedynczy wiersz dla każdej liczby ujemnej. Poniżej znajduje się przykładowy 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)

I to jest mój pożądany wynik (liczby dodatnie dla każdego Salesid SUM()i negatywy otrzymują indywidualną linię zwracaną):

salesid    num
1          26.32
1          -13.00
2          47.35
3          -12.32
3          -43.23
3          -2.32
użytkownik2676140
źródło

Odpowiedzi:

26

Spróbuj tego:

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

Jeśli chcesz mieć obie sumwartości w jednym wierszu, musisz utworzyć funkcję maxValue(i minValue) i użyć jej jako sum(maxValue(0, num))i sum(minValue(0, num)). Jest to opisane w: Czy istnieje funkcja Max w SQL Server, która przyjmuje dwie wartości, takie jak Math.Max ​​w .NET?

Marco
źródło
8
Naprawiłem zapytanie. Potrzebne UNION ALLteż nie UNION.
ypercubeᵀᴹ
24

To też działa:

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

Założenia:

  • Identyfikator zaczyna się od 1, więc można go użyć THEN 0. salesid ELSE salesid+id+1też by działał
  • 0 jest uważane za liczbę dodatnią, stąd >= 0( Czy zero jest dodatnie czy ujemne? ). Chociaż x+0=xwydaje się, że =znak jest niepotrzebny, pomaga pamiętać, że ta sprawa nie została zapomniana i jak obsługiwane jest 0 (jako SUMA lub jako pojedynczy wiersz). Jeśli the SUM() of all positive numbersoznacza SUM of strictly positive numbers(tj.> 0), =to nie jest potrzebne.

Musi zostać przetestowany z rzeczywistymi danymi i indeksami, ale przy zaledwie 1 skanie tabeli, wydajność może być nieco lepsza w niektórych przypadkach.

Brak indeksu wydaje się mieć mniejszy wpływ na to zapytanie dotyczące danych testowych poniżej:

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
źródło
Możesz uprościć klauzulę grupy za pomocą iif w następujący sposób: GROUP BY salesid, iif(num >= 0, 0, id) Fajne zapytanie.
user2023861,
1
Tak, ale OP musiałby najpierw zainstalować SQL Server 2012. IIF zaczyna się od SQL Server 2012: msdn.microsoft.com/en-us/library/hh213574.aspx . OP otagował swoje pytanie SQL Server 2008.
Julien Vavasseur