Как выполнить группировку в SQL Server для определенного вывода

#sql #sql-server

#sql #sql-сервер

Вопрос:

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

Структура таблицы

 | Inserted On | IsRegistered |
 ------------- -------------- 
| 10-01-2020  | 1            |
| 15-01-2020  | 1            |
| 17-01-2020  | null         |
| 17-02-2020  | 1            |
| 21-02-2020  | null         |   
| 04-04-2020  | null         |
| 18-04-2020  | null         |
| 19-04-2020  | 1            |
 

Исключенный вывод

 | Inserted On | Registered | Not Registered
 ------------- ------------ ---------------
| Jan         |     2      |    1
| Feb         |     1      |    1
| Apr         |     1      |    2
 

Я попытался выполнить обычную группировку, но не получил желаемого результата

 SELECT
    DATENAME(MONTH, dateinserted) AS [MonthName], COUNT(ISRegistered)
FROM
    tablename 
GROUP BY
    (DATENAME(MONTH, dateinserted))
 

Примечание: здесь null рассматривается как не зарегистрированный

Комментарии:

1. Вы говорите, что это не дало желаемого результата; что с ним не так? Ваши ожидаемые результаты имеют 3 столбца, но вы определяете только 2 в своей попытке. Что случилось с NotRegistered ?

2. Вы выбрали нефункционирующий код. По крайней мере, исправьте это, чтобы оно работало для следующего пользователя

3. @SteveC Гордон Линофф уже предоставил исправление

Ответ №1:

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

 select year(inserted_on), month(inserted_on),
       coalesce(sum(is_registered), 0) as num_registered,
       sum(case when is_registered is null then 1 else 0 end) as num_not_registered
from tablename
group by year(inserted_on), month(inserted_on)
order by year(inserted_on), month(inserted_on);
 

Примечание: Если вам действительно нужно имя месяца и вы хотите объединить данные за разные годы (что кажется маловероятным, но . . . ), тогда вы можете использовать:

 select datename(month, inserted_on),
       coalesce(sum(is_registered), 0) as num_registered,
       sum(case when is_registered is null then 1 else 0 end) as num_not_registered
from tablename
group by datename(month, inserted_on)
order by month(min(inserted_on));
 

Комментарии:

1. @Gordon Linoff попробовал приведенный выше запрос, но получил ошибку — бит типа данных операнда недопустим для оператора sum. нужно ли мне приводить как int ?

2. @VishalDhasal . . . Да, вам нужно cast() int .

3. @Larnu . , , Это только извлечение месяца для сортировки.

Ответ №2:

ГРУППА ПО должна включать как год, так и месяц (чтобы не было перекрытия), а также ИМЯ ДАТЫ (для отображения). Что-то вроде этого

 drop table if exists #tablename;
go
create table #tablename(dateinserted date, ISRegistered int);
insert #tablename values 
('2020-12-01', 0),
('2020-11-02', 1),
('2020-11-03', 1),
('2020-12-01', 1),
('2020-12-03', 1),
('2020-11-02', 0);

select year(dateinserted) yr,
       datename(month, dateinserted) AS [MonthName], 
       sum(ISRegistered) Registered ,
       sum(1-ISRegistered) [Not Registered]
from #tablename 
group by year(dateinserted), month(dateinserted), datename(month, dateinserted)
order by year(dateinserted), month(dateinserted);
 
 yr      MonthName   Registered  Not Registered
2020    November    2           1
2020    December    2           1