SQL Server Как вернуть NULL вместо 0, если значение GROUPED не имеет строк в источнике - PullRequest
0 голосов
/ 12 мая 2018

Вот SQL Fiddle с исходными данными, то, что я пробовал до сих пор, и что я ожидаю получить в качестве вывода.http://sqlfiddle.com/#!18/daf90/2

У меня есть таблица GameWinnings, в которой есть строки, содержащие имя участника, сыгранный им раунд и сумму выигрыша в этом раунде.

Мне нужно подготовить отчетсуммирует все выигрыши за раунд по участнику.

Условие, в котором я застрял, заключается в том, что если участник не играл в определенном раунде, то RoundWinningsAmount для этого раунда должно быть NULLне 0.Я думаю, что CROSS APPLY или PIVOT / UNPIVOT могли бы это сделать, но пока не смогли его зафиксировать.

Вот таблица и исходные данные, за которыми следуют оператор задачи и ожидаемый результат по сравнению сто, что я пробовал.

CREATE TABLE dbo.GameWinnings
(
    Contestant varchar(100) NOT NULL,
    GameRound int NOT NULL,
    RoundWinningsAmount numeric(38, 6) NULL
);

INSERT INTO dbo.GameWinnings (Contestant,GameRound, RoundWinningsAmount) 
VALUES('Ms Junaiqua',2,33333);
INSERT INTO dbo.GameWinnings (Contestant,GameRound, RoundWinningsAmount) 
VALUES('Mr Wang',1,NULL);
INSERT INTO dbo.GameWinnings (Contestant,GameRound, RoundWinningsAmount) 
VALUES('Mr Wang',1,NULL);
INSERT INTO dbo.GameWinnings (Contestant,GameRound, RoundWinningsAmount) 
VALUES('Mr Wang',1,100);
INSERT INTO dbo.GameWinnings (Contestant,GameRound, RoundWinningsAmount) 
VALUES('Mr Wang',2,NULL);
INSERT INTO dbo.GameWinnings (Contestant,GameRound, RoundWinningsAmount) 
VALUES('Thad Chad ',1,99);
INSERT INTO dbo.GameWinnings (Contestant,GameRound, RoundWinningsAmount) 
VALUES('Thad Chad ',1,1);
INSERT INTO dbo.GameWinnings (Contestant,GameRound, RoundWinningsAmount) 
VALUES('Thad Chad ',1,NULL);
INSERT INTO dbo.GameWinnings (Contestant,GameRound, RoundWinningsAmount) 
VALUES('Thad Chad ',2,50);
INSERT INTO dbo.GameWinnings (Contestant,GameRound, RoundWinningsAmount) 
VALUES('Thad Chad ',2,150);
INSERT INTO dbo.GameWinnings (Contestant,GameRound, RoundWinningsAmount) 
VALUES('Thad Chad ',2,NULL);
INSERT INTO dbo.GameWinnings (Contestant,GameRound, RoundWinningsAmount) 
VALUES('Thad Chad ',2,NULL);
INSERT INTO dbo.GameWinnings (Contestant,GameRound, RoundWinningsAmount) 
VALUES('Thad Chad ',3,300);

CREATE TABLE ExpectedOutput
(
Contestant varchar(100) NOT NULL,
Round_1_Winnings numeric(38, 6) NULL,
Round_2_Winnings numeric(38, 6) NULL,
Round_3_Winnings numeric(38, 6) NULL
); 

-- Expected output
INSERT INTO ExpectedOutput VALUES ('Mr Wang', 100 , 0 , NULL)
INSERT INTO ExpectedOutput VALUES ('Ms Junaiqua', NULL , 33333 , NULL)
INSERT INTO ExpectedOutput VALUES ('Thad Chad', 100 , 200 , 300)

Если вы делаете SELECT *, тогда это данные.

enter image description here

Постановка задачи и требования

В игре 3 раунда.Таким образом, значение столбца GameRound всегда будет только 1 или 2 или 3.

  1. Создать набор результатов по участнику, который суммирует каждого участника, выигравшего в каждом раунде
  2. Если участник не имеетучастие в определенном раунде, значение СУММ для этого раунда должно быть NULL, а не 0

Таким образом, в приведенных выше данных образца

  1. г-нВан играл в 1 и 2 раунде, но не в 3 раунде. Поэтому раунд 3 SUM должен быть NULL, а не 0.Раунд 2 SUM должен быть 0 с тех пор, как он играл во 2 раунде, но не выиграл никаких денег.
  2. Г-жа Junaiqua играла только во 2 раунде, но не в раунде1 или 3 раунд, поэтому раунд 1 и раунд 3 SUM должны быть NULL, а не 0.
  3. Тад Чад сыграл за все 3 раунда, поэтому все 3 раунда должныимеют значение SUM.

То, что я пробовал

-- Current query I've tried to get desired output.
-- The query is returning 0, instead of NULL for Rounds where Contestant didn't participate.
-- I know that this is happening because I am returning 0 in the ELSE of the CASE.
-- Not sure how to fix it. 
SELECT
    Contestant,
    SUM ( CASE WHEN GameRound = 1 THEN RoundWinningsAmount ELSE 0 END) Round_1_Winnings,
    SUM ( CASE WHEN GameRound = 2 THEN RoundWinningsAmount ELSE 0 END) Round_2_Winnings,
    SUM ( CASE WHEN GameRound = 3 THEN RoundWinningsAmount ELSE 0 END) Round_3_Winnings
FROM dbo.GameWinnings
GROUP BY Contestant 

Ожидаемый результат в сравнении с фактическим выходом.

Значения в красном должны бытьзначения показаны зеленым цветом.

enter image description here

Ответы [ 5 ]

0 голосов
/ 14 мая 2018

Вам просто нужно изменить NULL на ноль перед агрегацией.

Стандартное решение SQL, работающее на каждой СУБД:

SELECT
   Contestant,
   SUM ( CASE WHEN GameRound = 1 THEN COALESCE(RoundWinningsAmount,0) END) AS Round_1_Winnings,
   SUM ( CASE WHEN GameRound = 2 THEN COALESCE(RoundWinningsAmount,0) END) AS Round_2_Winnings,
   SUM ( CASE WHEN GameRound = 3 THEN COALESCE(RoundWinningsAmount,0) END) AS Round_3_Winnings
FROM dbo.GameWinnings
GROUP BY Contestant;
0 голосов
/ 12 мая 2018

Использование OUTER APPLY:

SELECT
  Contestant,
  SUM(CASE WHEN GameRound=1 THEN COALESCE(RoundWinningsAmount,s.p)END) Round1Win,
  SUM(CASE WHEN GameRound=2 THEN COALESCE(RoundWinningsAmount,s.p)END) Round2Win,
  SUM(CASE WHEN GameRound=3 THEN COALESCE(RoundWinningsAmount,s.p)END) Round3Win
FROM dbo.GameWinnings g
OUTER APPLY (SELECT TOP 1 0 FROM dbo.GameWinnings g2 
             WHERE g.Contestant = g2.Contestant
               AND g.GameRound = g2.GameRound) s(p)
GROUP BY Contestant;

Демоверсия DBFiddle

0 голосов
/ 12 мая 2018

Вы можете использовать запрос PIVOT , как показано ниже:

см. Демонстрационную версию

select * from 
(
    select 
        RoundWinnings=ISNULL(sum(RoundWinningsAmount),0),
        Contestant, 
        GameRound
    from GameWinnings
    group by Contestant, GameRound
)src
pivot
(
    max(RoundWinnings) 
    for GameRound in ([1],[2],[3])
 )p
0 голосов
/ 12 мая 2018

Попробуйте:

SELECT
Contestant,
SUM ( CASE WHEN b.Rounds = 1 THEN isnull(RoundWinningsAmount, 0) END) Round_1_Winnings,
SUM ( CASE WHEN b.Rounds = 2 THEN isnull(RoundWinningsAmount, 0) END) Round_2_Winnings,
SUM ( CASE WHEN b.Rounds = 3 THEN isnull(RoundWinningsAmount, 0) END) Round_3_Winnings
FROM dbo.GameWinnings a
LEFT JOIN (
          SELECT DISTINCT GameRound as rounds 
          FROM dbo.GameWinnings
        ) b
ON a.GameRound = b.rounds
GROUP BY Contestant;

Вы создаете все раунды и присоединяетесь к ним, чтобы поймать не шоу.Isnull предотвращает нулевое значение, когда участвует, но не выиграл.

Ваша скрипка

0 голосов
/ 12 мая 2018

Существует множество способов сделать это, но я бы порекомендовал использовать общее табличное выражение, а затем вносить изменения в зависимости от производительности / потребностей.

;WITH Results AS (
    SELECT
    Contestant,
    SUM ( CASE WHEN GameRound = 1 THEN RoundWinningsAmount ELSE 0 END) Round_1_Winnings,
    SUM ( CASE WHEN GameRound = 2 THEN RoundWinningsAmount ELSE 0 END) Round_2_Winnings,
    SUM ( CASE WHEN GameRound = 3 THEN RoundWinningsAmount ELSE 0 END) Round_3_Winnings
    FROM dbo.GameWinnings
    GROUP BY Contestant 
)
SELECT
    Contestant, 
    CASE WHEN Round_1_Winnings = 0 THEN NULL ELSE Round_1_Winnings END
    CASE WHEN Round_2_Winnings = 0 THEN NULL ELSE Round_2_Winnings END
    CASE WHEN Round_3_Winnings = 0 THEN NULL ELSE Round_3_Winnings END
FROM Results;  
...