2016-10-20 7 views
2

Я довольно смутно знаком с SQL. Я использую SQL Server 2012.Как сгруппировать только по месяцам и годам

У меня есть эта таблица:

|Id | SiteId| SiteDesc |IsNormal|  DateReview   |FrequencyId| 
|3379|  5|  colon | 1 | 2016-09-10 00:00:00.000| 1  |  
|3381|  5|  colon | 0 | 2016-09-15 00:00:00.000| 1  |  
|3382|  5|  colon | 1 | 2016-09-21 00:00:00.000| 1  | 

|3489|  5|  colon | 0 | 2016-08-10 00:00:00.000| 1  |  
|3851|  5|  colon | 1 | 2016-08-16 00:00:00.000| 1  | 

|3537|  2|  dogon | 1 | 2016-05-05 00:00:00.000| 1  |  
|3863|  2|  dogon | 1 | 2016-05-20 00:00:00.000| 1  |  

IsNormal колонка имеет BIT типа данных.

Мне нужно сгруппировать таблицу SiteId и DateReview (только месяц и год). Если в столбце IsNormal хотя бы одна строка имеет свойство false, в сгруппированной таблице оно должно быть False.

Здесь желаемый сгруппированный стол:

| SiteId| SiteDesc |IsNormal|  DateReview   |FrequencyId| 
|  5|  colon | 0 | 2016-09-10 00:00:00.000| 1  |   
|  5|  colon | 0 | 2016-08-10 00:00:00.000| 1  |  
|  2|  dogon | 1 | 2016-05-05 00:00:00.000| 1  |  

Спасибо заранее.

+1

@gaurav Любой элемент в элементе select с группой должен быть либо в группе, либо в совокупности: это не соответствует этому правилу. – Richard

ответ

3

SQL Server может не агрегирует bit столбцы как есть, так что бросайте его int первым, а затем использовать MIN, а затем бросил его обратно в bit.

Группировка по месяцам Я использую следующую формулу:

DATEADD(month, DATEDIFF(month, '20010101', DateReview), '20010101') 

Вы можете выбрать любую дату якорный вместо «20010101», это может быть любой первый день месяца. Идея проста. DATEDIFF(month,...) вычисляет количество месяцев между датой привязки и значением из таблицы. Это целое число - сколько раз пересекалась граница месяца. Затем это число добавляется к дате привязки. Результатом этого выражения является значение DateReview, усеченное до первого дня месяца.

Запрос

SELECT 
    SiteId 
    ,MIN(SiteDesc) AS SiteDesc 
    ,CAST(MIN(CAST(IsNormal AS int)) AS bit) AS IsNormal 
    ,MIN(DateReview) AS DateReview 
    ,MIN(FrequencyId) AS FrequencyId 
FROM T 
GROUP BY 
    SiteId 
    ,DATEADD(month, DATEDIFF(month, '20010101', DateReview), '20010101') 
+1

Любопытно, почему бы не «GROUP BY YEAR (DateReview), MONTH (DateReview)'? – Eric

+1

@ Эрик, в этом случае нет никакой разницы. Формула с 'DATEDIFF' является более общей. Вы можете поместить 'week' /' quarter'/'hour'/etc вместо' month', чтобы сгруппировать другим интервалом. –

3

Использование year() и month():

select SiteId, min(SiteDesc) as SiteDesc, 
     min(case when IsNormal = 0 then 0 else 1 end) as IsNormal, 
     min(DateReview) as DateReview, 
     min(FrequencyId) as FrequencyId 
from t 
group by SiteId, year(DateReview), month(DateReview) 
order by min(DateReview) desc; 

Это просто использует год и месяц для агрегации. Затем он вытягивает значения столбца, используя функцию агрегации. Для DateReview соответствующей функцией является min().

Смежные вопросы