Это за какой-то данный год?Я предполагаю, что вы хотите график на текущий год.Если вам нужен будущий год, вы всегда можете изменить DECLARE @now
, чтобы указать любую будущую дату.
«Один раз в 2 недели» (обычно известный как «раз в две недели») не вписывается в ежемесячные сегменты.(кроме февраля в не високосный год).Должно ли это быть изменено на «Дважды в месяц»?
Кроме того, почему бы не сохранить коэффициент в таблице частот, добавив столбец с именем «PerMonth»?Тогда вам нужно иметь дело только с ежедневными и ежеквартальными делами (и это произвольный выбор, что это произойдет только в январе, апреле и т. Д.?).
Предполагая, что что-то из этого является гибким, я хотел бы предложить следующее, предполагая это очень незначительное изменение в схеме таблицы:
USE tempdb;
GO
CREATE TABLE dbo.Frequency
(
Id INT PRIMARY KEY,
Frequency VARCHAR(32),
PerMonth TINYINT
);
CREATE TABLE dbo.EmailBlast
(
Id INT,
FrequencyId INT,
UserId INT
);
И этот пример данных:
INSERT dbo.Frequency(Id, Frequency, PerMonth)
SELECT 1, 'Daily', NULL
UNION ALL SELECT 2, 'Weekly', 4
UNION ALL SELECT 3, 'Monthly', 1
UNION ALL SELECT 4, 'Quarterly', NULL
UNION ALL SELECT 5, 'Twice a month', 2;
INSERT dbo.EmailBlast(Id, FrequencyId, UserId)
SELECT 1, 5, 1
UNION ALL SELECT 2, 2, 1
UNION ALL SELECT 3, 4, 1;
Мы можем выполнить это, используя очень сложный запрос (но нам не нужно жестко кодировать эти номера месяцев):
DECLARE @now DATE = CURRENT_TIMESTAMP;
DECLARE @Jan1 DATE = DATEADD(MONTH, 1-MONTH(@now), DATEADD(DAY, 1-DAY(@now), @now));
WITH n(m) AS
(
SELECT TOP 12 m = number
FROM master.dbo.spt_values
WHERE number > 0 GROUP BY number
),
months(MNum, MName, StartDate, NumDays) AS
( SELECT m, mn = CONVERT(CHAR(3), DATENAME(MONTH, DATEADD(MONTH, m-1, @Jan1))),
DATEADD(MONTH, m-1, @Jan1),
DATEDIFF(DAY, DATEADD(MONTH, m-1, @Jan1), DATEADD(MONTH, m, @Jan1))
FROM n
),
grp AS
(
SELECT UserId, MName, c = SUM (
CASE x.Id WHEN 1 THEN NumDays
WHEN 4 THEN CASE WHEN MNum % 3 = 1 THEN 1 ELSE 0 END
ELSE x.PerMonth END )
FROM months CROSS JOIN (SELECT e.UserId, f.*
FROM EmailBlast AS e
INNER JOIN Frequency AS f
ON e.FrequencyId = f.Id) AS x
GROUP BY UserId, MName
),
cumulative(UserId, total) AS
(
SELECT UserId, SUM(c)
FROM grp GROUP BY UserID
),
pivoted AS
(
SELECT * FROM (SELECT UserId, c, MName FROM grp) AS grp
PIVOT(MAX(c) FOR MName IN (
[Jan],[Feb],[Mar],[Apr],[May],[Jun],[Jul],[Aug],[Sep],[Oct],[Nov],[Dec])
) AS pvt
)
SELECT p.*, c.total
FROM pivoted AS p
LEFT OUTER JOIN cumulative AS c
ON p.UserId = c.UserId;
Результаты:
UserId Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec total
1 7 6 6 7 6 6 7 6 6 7 6 6 76
Очиститьup:
DROP TABLE dbo.EmailBlast, dbo.Frequency;
GO
На самом деле предложенное мной изменение схемы на самом деле мало что дает, а просто экономит две дополнительные ветви CASE
внутри grp
CTE.Арахис, общий.