三角联赢!
SELECT account,EndOfMonth,username
FROM (
SELECT Ends.*, h.*
,ROW_NUMBER() OVER (PARTITION BY h.account,Ends.EndOfMonth ORDER BY h.assigned DESC) AS RowNumber
FROM (
SELECT [Year],[Month],MAX(DATE) AS EndOfMonth
FROM #dim
GROUP BY [Year],[Month]
) Ends
CROSS JOIN (
SELECT account, MAX(assigned) AS MaxAssigned
FROM #histories
GROUP BY account
) ac
JOIN #histories h ON h.account = ac.account
AND Year(h.assigned) = ends.[Year]
AND Month(h.assigned) <= ends.[Month] --triangle join for the win!
AND EndOfMonth < DATEADD(month, 1, Maxassigned)
) Results
WHERE RowNumber = 1
ORDER BY account,EndOfMonth;
结果是:
account EndOfMonth username
ACCOUNT1 2017-01-31 PETER
ACCOUNT1 2017-02-28 PETER
ACCOUNT1 2017-03-31 DAVE
ACCOUNT1 2017-04-30 DAVE
ACCOUNT1 2017-05-31 FRED
ACCOUNT1 2017-06-30 FRED
ACCOUNT1 2017-07-31 FRED
ACCOUNT1 2017-08-31 JAMES
ACCOUNT2 2017-01-31 PHIL
ACCOUNT2 2017-02-28 PHIL
ACCOUNT2 2017-03-31 PHIL
ACCOUNT2 2017-04-30 JAMES
ACCOUNT2 2017-05-31 PHIL
此处的交互式执行计划。
I / O和TIME状态(逻辑读取后将所有零值都截断):
(13 row(s) affected)
Table 'Worktable'. Scan count 3, logical reads 35.
Table 'Workfile'. Scan count 0, logical reads 0.
Table '#dim'. Scan count 1, logical reads 4.
Table '#histories'. Scan count 1, logical reads 1.
SQL Server Execution Times:
CPU time = 0 ms, elapsed time = 3 ms.
查询以创建所需的临时表并测试我建议的T-SQL语句:
IF OBJECT_ID('tempdb..#histories') IS NOT NULL
DROP TABLE #histories
CREATE TABLE #histories (
username VARCHAR(10)
,account VARCHAR(10)
,assigned DATE
);
INSERT INTO #histories
VALUES
('PHIL','ACCOUNT1','2017-01-04'),
('PETER','ACCOUNT1','2017-01-15'),
('DAVE','ACCOUNT1','2017-03-04'),
('ANDY','ACCOUNT1','2017-05-06'),
('DAVE','ACCOUNT1','2017-05-07'),
('FRED','ACCOUNT1','2017-05-08'),
('JAMES','ACCOUNT1','2017-08-05'),
('DAVE','ACCOUNT2','2017-01-02'),
('PHIL','ACCOUNT2','2017-01-18'),
('JOSH','ACCOUNT2','2017-04-08'),
('JAMES','ACCOUNT2','2017-04-09'),
('DAVE','ACCOUNT2','2017-05-06'),
('PHIL','ACCOUNT2','2017-05-07');
DECLARE @StartDate DATE = '20170101'
,@NumberOfYears INT = 2;
-- prevent set or regional settings from interfering with
-- interpretation of dates / literals
SET DATEFIRST 7;
SET DATEFORMAT mdy;
SET LANGUAGE US_ENGLISH;
DECLARE @CutoffDate DATE = DATEADD(YEAR, @NumberOfYears, @StartDate);
-- this is just a holding table for intermediate calculations:
IF OBJECT_ID('tempdb..#dim') IS NOT NULL
DROP TABLE #dim
CREATE TABLE #dim (
[date] DATE PRIMARY KEY
,[day] AS DATEPART(DAY, [date])
,[month] AS DATEPART(MONTH, [date])
,FirstOfMonth AS CONVERT(DATE, DATEADD(MONTH, DATEDIFF(MONTH, 0, [date]), 0))
,[MonthName] AS DATENAME(MONTH, [date])
,[week] AS DATEPART(WEEK, [date])
,[ISOweek] AS DATEPART(ISO_WEEK, [date])
,[DayOfWeek] AS DATEPART(WEEKDAY, [date])
,[quarter] AS DATEPART(QUARTER, [date])
,[year] AS DATEPART(YEAR, [date])
,FirstOfYear AS CONVERT(DATE, DATEADD(YEAR, DATEDIFF(YEAR, 0, [date]), 0))
,Style112 AS CONVERT(CHAR(8), [date], 112)
,Style101 AS CONVERT(CHAR(10), [date], 101)
);
-- use the catalog views to generate as many rows as we need
INSERT #dim ([date])
SELECT d
FROM (
SELECT d = DATEADD(DAY, rn - 1, @StartDate)
FROM (
SELECT TOP (DATEDIFF(DAY, @StartDate, @CutoffDate)) rn = ROW_NUMBER() OVER (
ORDER BY s1.[object_id]
)
FROM sys.all_objects AS s1
CROSS JOIN sys.all_objects AS s2
-- on my system this would support > 5 million days
ORDER BY s1.[object_id]
) AS x
) AS y;
/* The actual SELECT statement to get the results we want! */
SET STATISTICS IO, TIME ON;
SELECT account,EndOfMonth,username
FROM (
SELECT Ends.*, h.*
,ROW_NUMBER() OVER (PARTITION BY h.account,Ends.EndOfMonth ORDER BY h.assigned DESC) AS RowNumber
FROM (
SELECT [Year],[Month],MAX(DATE) AS EndOfMonth
FROM #dim
GROUP BY [Year],[Month]
) Ends
CROSS JOIN (
SELECT account, MAX(assigned) AS MaxAssigned
FROM #histories
GROUP BY account
) ac
JOIN #histories h ON h.account = ac.account
AND Year(h.assigned) = ends.[Year]
AND Month(h.assigned) <= ends.[Month] --triangle join for the win!
AND EndOfMonth < DATEADD(month, 1, Maxassigned)
) Results
WHERE RowNumber = 1
ORDER BY account,EndOfMonth;
SET STATISTICS IO, TIME OFF;
--IF OBJECT_ID('tempdb..#histories') IS NOT NULL DROP TABLE #histories
--IF OBJECT_ID('tempdb..#dim') IS NOT NULL DROP TABLE #dim
2017-05
因为他拥有该帐户,2017-05-07
并且没有后续的持有人?