Группировка результатов SQL из объединения (SQL Server) - PullRequest
0 голосов
/ 10 мая 2018

Я использую повторяющийся запрос с group by и union, чтобы получить мой результат, но результат не отображается так, как я хочу.

Запрос:

select  
    league , 
    count(*) as total_1   
from 
    Games  
where
    score_away is not null 
    and score_home is not null   
group by 
    League

union 

select 
    league , 
    count(*) as total_2    
from 
    Games  
where
    score_away is null 
    and score_home is null   
group by 
    League

Таблица игр

 leugue      gameID     score_home     score_away
-------------------------------------------------
       1        10           2               0
       1        11           1               1
       1        12           NUll            NULL
       2        13           2               0
       1        14           NUll            NULL
       1        15           1               1
       2        16           2               2
       2        17           2               4

Текущие результаты:

    League     total1
------------------------
        1        3
        1        2  
        2        3

Ожидаемые результаты:

    League     total1    total2
-------------------------------
        1        3        2
        2        3        0

Ответы [ 2 ]

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

На самом деле вы можете делать такие вещи без UNION или JOINS.
Просто используйте GROUP BY и SUM рассчитанную 1 или 0 (через CASE или IIF).

Тогда будет проще добавлять дополнительные итоги, используя тот же трюк.

select 
 league, 
 sum(case when score_away is not null and score_home is not null then 1 else 0 end) as total1_has_away_and_home,
 sum(iif(score_away is null and score_home is null, 1, 0)) as total2_no_away_or_home
from Games g
group by league;

Пример фрагмента:

declare @Games table (league int, gameID int, score_home int, score_away int);

insert into @Games (league, gameID, score_home, score_away) values
(1, 10, 2, 0),(1, 11, 1, 1),(1, 12, NULL, NULL),(1, 14, NULL, NULL),(1, 15, 1, 1),
(2, 13, 2, 0),(2, 16, 2, 2),(2, 17, 2, 4);

select 
 league, 
 sum(case when score_away is not null and score_home is not null then 1 else 0 end) as total1_has_away_and_home,
 sum(case when score_away is null and score_home is null then 1 else 0 end) as total2_no_away_or_home
from @Games g
group by league;

Для этого все еще можно использовать UNION ALL.
Просто добавив дополнительное поле квыбирает используемый в объединении.
Затем группирует этот результат.

Например:

select league, sum(total_1) as total_1, sum(total_2) as total_2 
from 
(
    select league, count(*) as total_1, 0 as total_2
    from Games
    where score_away is not null
      and score_home is not null
    group by league

    union all

    select league, 0, count(*)
    from Games
    where score_away is null
      and score_home is null
    group by league
) q
group by league;

Но это менее эффективный способ сделать это.
(Кстати, UNION удаляет дубликаты, а UNION ALL - нет)

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

Если вам нужны все результаты (без удаления дубликатов), вы можете использовать UNION ALL вместо UNION.В этом случае результаты станут следующими:

   League     total1
------------------------
        1        20
        2        10
        1        40
        2        10

Однако, чтобы получить желаемый результат, вы можете попробовать:

SELECT
    league = COALESCE(Totals1.league, Totals2.league),
    total_1 = COALESCE(Totals1.total_1, 0),
    total_2 = COALESCE(Totals2.total_2, 0)
FROM
    (SELECT league, COUNT(*) as total_1
     FROM Games
     WHERE score_away is not null and score_home is not null
     GROUP BY league) as Totals1
    FULL JOIN
    (SELECT league, COUNT(*) as total_2
     FROM Games
     WHERE score_away is null and score_home is null
     GROUP BY league) as Totals2
    ON Totals1.league = Totals2.league;

Редактировать: только что исправили итоги врезультат должен возвращать 0 вместо NULL.

Редактировать 2: На основании вашего запрошенного расширения в ваших комментариях я изменил свой запрос, включив в него процентные вычисления следующим образом:

SELECT
    league = COALESCE(Totals1.league, Totals2.league),
    total_1 = COALESCE(Totals1.total_1, 0),
    total_2 = COALESCE(Totals2.total_2, 0),
    percent_1 = 100 * COALESCE(Totals1.total_1, 0) / (COALESCE(Totals1.total_1, 0) + COALESCE(Totals2.total_2, 0)),
    percent_2 = 100 * COALESCE(Totals2.total_2, 0) / (COALESCE(Totals1.total_1, 0) + COALESCE(Totals2.total_2, 0))
FROM
    (SELECT league, COUNT(*) AS total_1
     FROM Games
     WHERE score_away IS NOT NULL AND score_home IS NOT NULL
     GROUP BY league) AS Totals1
    FULL JOIN
    (SELECT league, COUNT(*) as total_2
     FROM Games
     WHERE score_away IS NULL AND score_home IS NULL
     GROUP BY league) AS Totals2
    ON Totals1.league = Totals2.league
ORDER BY percent_1;

Чтобы сделатьПроцент вычислений более читабелен, вы можете поместить исходный запрос как подзапрос в табличное выражение.Например:

SELECT
    league,
    total_1,
    total_2,
    percent_1 = 100 * total_1 / (total_1 + total_2),
    percent_2 = 100 * total_2 / (total_1 + total_2)
FROM
    (
        SELECT
            league = COALESCE(Totals1.league, Totals2.league),
            total_1 = COALESCE(Totals1.total_1, 0),
            total_2 = COALESCE(Totals2.total_2, 0)
        FROM
            (SELECT league, COUNT(*) AS total_1
             FROM Games
             WHERE score_away IS NOT NULL AND score_home IS NOT NULL
             GROUP BY league) AS Totals1
            FULL JOIN
            (SELECT league, COUNT(*) as total_2
             FROM Games
             WHERE score_away IS NULL AND score_home IS NULL
             GROUP BY league) AS Totals2
            ON Totals1.league = Totals2.league
    ) AS Sub
ORDER BY percent_1;

Мне лично не нравятся сложные «анонимные» табличные выражения в предложении FROM, и я бы преобразовал их в общее табличное выражение, например:

WITH
    Sub AS
    (
        SELECT
            league = COALESCE(Totals1.league, Totals2.league),
            total_1 = COALESCE(Totals1.total_1, 0),
            total_2 = COALESCE(Totals2.total_2, 0)
        FROM
            (SELECT league, COUNT(*) AS total_1
                FROM Games
                WHERE score_away IS NOT NULL AND score_home IS NOT NULL
                GROUP BY league) AS Totals1
            FULL JOIN
            (SELECT league, COUNT(*) as total_2
                FROM Games
                WHERE score_away IS NULL AND score_home IS NULL
                GROUP BY league) AS Totals2
            ON Totals1.league = Totals2.league
    )
SELECT
    league,
    total_1,
    total_2,
    percent_1 = 100 * total_1 / (total_1 + total_2),
    percent_2 = 100 * total_2 / (total_1 + total_2)
FROM Sub
ORDER BY percent_1;

И при рефакторингеподобный запрос, я бы также преобразовал два других табличных выражения (два подзапроса SELECT в таблице игр) в общие табличные выражения:

WITH
    Totals1 AS
    (
        SELECT league, COUNT(*) AS total_1
        FROM Games
        WHERE score_away IS NOT NULL AND score_home IS NOT NULL
        GROUP BY league
    ),
    Totals2 AS
    (
        SELECT league, COUNT(*) as total_2
        FROM Games
        WHERE score_away IS NULL AND score_home IS NULL
        GROUP BY league
    ),
    Sub AS
    (
        SELECT
            league = COALESCE(Totals1.league, Totals2.league),
            total_1 = COALESCE(Totals1.total_1, 0),
            total_2 = COALESCE(Totals2.total_2, 0)
        FROM
            Totals1
            FULL JOIN Totals2 ON Totals1.league = Totals2.league
    )
SELECT
    league,
    total_1,
    total_2,
    percent_1 = 100 * total_1 / (total_1 + total_2),
    percent_2 = 100 * total_2 / (total_1 + total_2)
FROM Sub
ORDER BY percent_1;

Конечно, то же самое можно сделать с исходным запросомиз LukStorms, поместив его в общее табличное выражение:

WITH
    Sub AS
    (
        SELECT
            league,
            total_1 = SUM(CASE WHEN score_away IS NOT NULL AND score_home IS NOT NULL THEN 1 ELSE 0 END),
            total_2 = SUM(CASE WHEN score_away IS NULL AND score_home IS NULL THEN 1 ELSE 0 END)
        FROM Games
        GROUP BY league
    )
SELECT
    league,
    total_1,
    total_2,
    percent_1 = 100 * total_1 / (total_1 + total_2),
    percent_2 = 100 * total_2 / (total_1 + total_2)
FROM Sub
ORDER BY percent_1;

Опять же, в этом случае, как я вижу, запрос LukStorms короче, элегантнее и, вероятно, быстрее.

NB1: проценты в настоящее время являются целыми числами.Если вы хотите использовать дробные проценты, вы можете заменить 100 на 100,0

Примечание: при использовании общих табличных выражений (с помощью предложения WITH) в сценарии SQL или хранимой процедуре обратите внимание, что потребуется разделитьпредыдущий запрос (перед ключевым словом WITH) с точкой с запятой.В противном случае SQL Server будет выдавать ошибку с ошибкой.

...