我正在使用SQL Server 2012,并且拥有一个包含成员资格信息的数据库。我正在尝试编写SQL,它将计算每个月中存在的每种类型的成员,以便我可以报告成员资格是逐月上升还是下降。我的架构的简化版本是:
http://www.sqlfiddle.com/#!6/5fed2/1
CREATE TABLE MemberType
(
MemberTypeID INT,
Name VARCHAR(50)
);
CREATE TABLE Person
(
PersonID INT,
Name VARCHAR(50)
);
CREATE TABLE Invoice
(
InvoiceID INT,
DateStart DATE,
DateEnd DATE,
PersonID INT, --(FK) Person that purchased the membership
MemberTypeID INT, --(FK) Type of membership
);
INSERT MemberType (MemberTypeID,Name) VALUES (1,'Regular')
INSERT MemberType (MemberTypeID,Name) VALUES (2,'Special')
INSERT MemberType (MemberTypeID,Name) VALUES (3,'Honorary')
INSERT Person (PersonID,Name) VALUES (1,'Joe Smith')
INSERT Person (PersonID,Name) VALUES (2,'Anna Smith')
INSERT Person (PersonID,Name) VALUES (3,'Ted Williams')
INSERT Person (PersonID,Name) VALUES (4,'Bill Williams')
INSERT Invoice VALUES(1,'2011-5-1', '2012-1-1', 1, 1)
INSERT Invoice VALUES(2,'2010-1-1', '2013-1-1', 2, 2)
INSERT Invoice VALUES(3,'2012-2-1', '2013-2-1', 3, 1)
INSERT Invoice VALUES(4,'2009-1-1', '2011-5-1', 1, 1)
INSERT Invoice VALUES(5,'2011-1-1', '2012-5-1', 4, 1)
我试图将会员计入特定日期,如下所示:
DECLARE @RunDt DATE='2011-1-1'
SELECT
mt.Name [MemberType], @RunDt [Date], count(p.PersonID) [Count]
FROM MemberType mt
LEFT OUTER JOIN Invoice i ON i.MemberTypeID=mt.MemberTypeID
LEFT OUTER JOIN Person p ON p.PersonID=i.PersonID
WHERE @RunDt BETWEEN i.DateStart AND i.DateEnd
GROUP BY mt.Name
我认为这很接近,但我希望将荣誉类型包含在0中。我认为LEFT OUTER JOIN
会实现这一目标,但你不会。
这也仅适用于单个日期。我的下一步是将每个月的第1个查询的结果全部放在一个结果集中。
答案 0 :(得分:3)
通过在Invoice
子句中放置WHERE
表的过滤条件,您基本上已将OUTER JOIN
转换为INNER JOIN
。请尝试将此过滤条件放在ON
OUTER JOIN
Invoice
对SELECT
mt.Name AS [MemberType],
@RunDt AS [Date],
count(p.PersonID) AS [Count]
FROM dbo.MemberType AS mt
LEFT OUTER JOIN dbo.Invoice AS i
ON i.MemberTypeID=mt.MemberTypeID
AND @RunDt BETWEEN i.DateStart AND i.DateEnd
LEFT OUTER JOIN dbo.Person AS p
ON p.PersonID = i.PersonID
GROUP BY mt.Name;
的{{1}}条件中。
DECLARE @year INT = 2012;
;WITH x(d) AS
(
SELECT CONVERT(DATE, DATEADD(MONTH, n-1,
DATEADD(YEAR, @year-1900, '19000101')))
FROM
(
SELECT TOP (12) n = ROW_NUMBER() OVER
(ORDER BY [object_id])
FROM sys.all_objects
ORDER BY [object_id]
) AS y
)
SELECT
mt.[Name],
[Date] = x.d,
[Count] = COUNT(p.PersonID)
FROM x CROSS JOIN dbo.MemberType AS mt
LEFT OUTER JOIN dbo.Invoice AS i
ON i.MemberTypeID = mt.MemberTypeID
AND x.d BETWEEN i.DateStart AND i.DateEnd
LEFT OUTER JOIN dbo.Person AS p
ON p.PersonID = i.PersonID
GROUP BY mt.Name, x.d
ORDER BY x.d, mt.Name;
演示:
http://www.sqlfiddle.com/#!6/5fed2/2
如果你想在某一年的每个月都这样做:
{{1}}
SQLFiddle演示:
http://sqlfiddle.com/#!6/f5f84/2
有关无循环生成集的更多信息:
http://www.sqlperformance.com/2013/01/t-sql-queries/generate-a-set-1
http://www.sqlperformance.com/2013/01/t-sql-queries/generate-a-set-2
http://www.sqlperformance.com/2013/01/t-sql-queries/generate-a-set-3