2016-10-13 3 views
0

скажем, у меня есть следующие данные:Суммируя значения в течение периода времени в SQL («окно качению»)

ContactDate Zip 
10-1-2016 90210 
10-7-2016 90211 
10-8-2016 90210 
10-8-2016 90211 

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

Я пытаюсь получить следующий результат:

BillingMonthStart Zip Count 
9-2-2016   90210 1 
10-2-2016   90210 1 
10-2-2016   90211 2 

Вот моя попытка (очевидно, структура таблицы отличается, я начну фиксируя пример выше):

select 
    C1.ContactDate, count(C1.ContactDate) 
from 
    dbo.contacts c1 join dbo.contacts C2 on 
     C2.contactdate between C1.ContactDate AND dateadd(day, 30, C1.ContactDate) 
     AND c1.account = c2.accountid 
    join payment.dbo.AccountBilling B on c1.accountid = B.AccountID 
where 
    c1.account = @accountid 
    and C1.ContactDate >= @start_date 
    and C1.ContactDate <= @end_date 
    and DAY(C1.ContactDate) = B.BillingDOM 
Group by C1.contactDate 

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

EDIT Прежде всего, извините за плохо сформированный вопрос. Я понял это (хотя я уверен, что есть лучшие способы). Вот что я сделал:

  1. получить биллинг месяц в переменных
  2. Используя рекурсивный КТР я произвел все даты выставления счетов (в пределах диапазона я заботилась о)
  3. Регистрации на столе Контакта данных с использованием between billingDate from # 2 и billingDate + 1 месяц
  4. Группируйте по дате оплаты и выберите счет .

Вот SQL:

DECLARE @start_date DateTime 
DECLARE @end_date DateTime 
DECLARE @accountid int 
DECLARE @billing_dom tinyint 

SET @start_date = '2016-01-01' 
SET @end_date = '2016-12-31' 
SET @accountid = 6045032; 

select @billing_dom = BillingDOM 
from Payment.dbo.AccountBilling 
where AccountID = @accountid; 


WITH cte_months AS 
(
    SELECT 
     BillingDate = CAST(CAST(datepart(yyyy, @start_date) AS varchar) + '-' + CAST(datepart(mm, @start_date) AS varchar) + '-' + CAST(@billing_dom AS varchar) AS DATETIME), 
     dt = @start_date 
    UNION ALL 
    SELECT 
     BillingDate = DateAdd(mm, 1, BillingDate), 
     dt = DATEADD(mm, 1, dt) 
    FROM 
     cte_months 
    WHERE 
     dt < DATEADD(mm, -1, @end_date) 
) 
--SELECT * FROM cte_months 


select 
    cte_months.BillingDate, count(C.ContactDate) as Contacts 
from 
    cte_months left join dbo.contacts C on 
     C.ContactDate between cte_months.BillingDate and dateadd(mm, 1, cte_months.BillingDate) 
where 
    C.accountid = @accountid 
Group by cte_months.BillingDate 
+1

Здесь отличное место, чтобы начать , http://spaghettidba.com/2015/04/24/how-to-post-a-t-sql-question-on-a-public-forum/ –

+0

Можете ли вы объяснить, как 9-2-2016 составляет 1 для 90210? –

+0

@ KannanKandasamy, потому что строка на 10-1-2016 является частью этого месяца. –

ответ

0

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

DECLARE @myTable TABLE (ContactDate DATE, Zip INT); 
INSERT @myTable VALUES ('10-1-2016', 90210), ('10-7-2016', 90211), ('10-8-2016', 90210), ('10-8-2016', 90211); 

DECLARE @myBilling TABLE (Zip INT, BillingDay INT); 
INSERT @myBilling VALUES (90210, 2), (90211, 2); 

SELECT CAST(CASE WHEN DATEPART(DAY, T.ContactDate) < B.BillingDay 
      THEN DATEADD(DAY, B.BillingDay - 1, DATEADD(MONTH, DATEDIFF(MONTH, 0, T.ContactDate) - 1, 0)) 
      ELSE DATEADD(DAY, B.BillingDay - 1, DATEADD(MONTH, DATEDIFF(MONTH, 0, T.ContactDate), 0)) 
     END AS DATE) BillingPeriod 
    , T.Zip 
    , COUNT(*) theCount 
FROM @myTable T 
JOIN @myBilling B ON B.Zip = T.Zip 
GROUP BY T.Zip 
     ,CASE WHEN DATEPART(DAY, T.ContactDate) < B.BillingDay 
       THEN DATEADD(DAY, B.BillingDay - 1, DATEADD(MONTH, DATEDIFF(MONTH, 0, T.ContactDate) - 1, 0)) 
       ELSE DATEADD(DAY, B.BillingDay - 1, DATEADD(MONTH, DATEDIFF(MONTH, 0, T.ContactDate), 0)) 
     END; 
0

Вы группировать по месяцам (28 до 31 дней), или это всегда 30 дней?

Если это всегда 30 дней, то группируйте это в дополнение к любым другим столбцам, не имеющим даты.

ceiling(cast(datediff(day,BillingMonthStart,ContactDate) AS FLOAT)/30) 

Это даст вам число 30 дней с интервалом между BillingMonthStart и ContactDate округление вверх. Тем не менее, он считает контакт в тот же день, что и 0, и включает 30-й день. Если вы хотите, чтобы 30-й день, чтобы новая группа, то:

ceiling((cast(datediff(day,BillingMonthStart,ContactDate) AS FLOAT)+1)/30) 

Если вы хотите, чтобы это было на протяжении месяца вместо статических 30 дней, а затем:

datediff(month,@BillingMonthStart,@ContactDate) - CASE 
     WHEN datepart(day,@BillingMonthStart) > datepart(day,@ContactDate) THEN 1 
     ELSE 0 
     END 
+0

по месяцам. Я добавил собственный ответ в верхней части. Спасибо за помощь, хотя – Dave

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