Đây có phải là bất kỳ năm nào không? Tôi sẽ giả sử bạn muốn lịch trình cho năm hiện tại. Nếu bạn muốn một năm trong tương lai, bạn luôn có thể thay đổi DECLARE @now
để chỉ định bất kỳ ngày nào trong tương lai.
"Một lần trong 2 tuần" (thường được gọi là "hai tuần") không phù hợp với nhóm hàng tháng (ngoại trừ tháng 2 trong năm không phải là năm nhuận). Có nên thay đổi thành "Hai lần một tháng" không?
Ngoài ra, tại sao không lưu hệ số trong bảng Tần suất, thêm cột có tên "PerMonth"? Sau đó, bạn chỉ phải đối phó với các trường hợp hàng ngày và hàng quý (và nó là một sự lựa chọn tùy ý rằng điều này sẽ xảy ra chỉ trong tháng Giêng, tháng tư, và như vậy?).
Giả sử rằng một số trong số này là linh hoạt, đây là những gì tôi sẽ đề nghị, giả sử thay đổi này rất nhỏ cho schema bảng:
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
);
Và dữ liệu mẫu này:
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;
Chúng ta có thể thực hiện điều này bằng cách sử dụng truy vấn rất phức tạp (nhưng chúng tôi không phải mã hóa cứng những tháng đó):
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;
Kết quả:
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
Dọn dẹp:
DROP TABLE dbo.EmailBlast, dbo.Frequency;
GO
Trong thực tế, sự thay đổi schema tôi đề nghị không thực sự mua bạn nhiều, nó chỉ giúp bạn tiết kiệm thêm hai CASE
chi nhánh bên trong grp
CTE. Đậu phộng, tổng thể.
Bạn có chắc chắn hiển thị đúng dữ liệu của mình không? Chỉ vì một cái gì đó được cấu hình để đi ra ngoài một thời gian nhất định một khoảng thời gian không có nghĩa là nó đã làm. Tôi có thể sai về những gì bạn đang làm nhưng tôi nghĩ sẽ tốt hơn nếu đếm số vụ nổ thực tế mỗi tháng ... – NotMe
Trường hợp cuối cùng của bạn không nên là WHEN FrequencyId = 5 THEN 2 –
@chris, Những vụ nổ thực sự có thể lên lịch. Màn hình hiển thị số lần email sẽ được gửi cùng với tần số hiện tại. Tôi tin tưởng, đây là một yêu cầu nên không có điểm cố gắng để xem điều đó đúng hay sai. đã từng trải qua rồi. –