我在SQL Server DB中有表:
ID Open_date Close_date
1 01-01-2010 01-03-2010
2 21-01-2011 12-02-2011
3 01-03-2010 NULL
4 10-01-2010 NULL
我需要做一些将返回的T-SQL查询:
Month Year Open Close
01 2010 2 0
02 2010 0 0
03 2010 0 1
04 2010 0 0
05 2010 0 0
06 2010 0 0
07 2010 0 0
08 2010 0 0
09 2010 0 0
10 2010 0 0
11 2010 0 0
12 2010 0 0
01 2011 1 0
02 2011 0 1
结果集中的条目数等于来自DB的表的“Open_date”和“Close_date”列的最小值与来自相同列的最大值之间的月数。问题是如何从两个日期列中查找最小值和最大值,然后生成从最小值到最大值的日期,然后使用此临时表(或它将是什么)来计算临时表中每个日期的打开和关闭条目的数量。
答案 0 :(得分:1)
我之前做了一个例子并最终没有发布它,但回来后决定发布它:)
-- Sample Data
CREATE TABLE #SampleVals ( ID int, Open_Date Date, Close_Date Date);
INSERT INTO #SampleVals(ID, Open_Date, Close_Date)
VALUES(1,'20100101','20100301'),
(2,'20110121','20110212'),
(3,'20100301', NULL),
(4,'20100110',NULL);
-- Get Start/End for full date range
DECLARE @Min Date, @Max Date;
SELECT @Min = DateAdd(dd,-1 * Day(MIN(Open_Date)) + 1, MIN(Open_Date)),
@Max = MAX(Close_Date)
FROM #SampleVals;
-- Query for values across entire range
WITH DateRange (StartDate,NextDate) AS (
SELECT DATEADD(MONTH, n-1, @Min),
DATEADD(MONTH, n, @Min)
FROM dbo.Number N
WHERE N.n <= DATEDIFF(MONTH,@Min,@Max) + 1
)
SELECT MONTH(DR.StartDate),
YEAR(DR.StartDate),
SUM(CASE WHEN S.Open_Date >= DR.StartDate Then 1 Else 0 END) AS [Open],
SUM(CASE WHEN S.Close_Date < DR.NextDate Then 1 Else 0 END) AS [Closed]
FROM DateRange DR
LEFT JOIN #SampleVals S ON S.Open_Date < DR.NextDate
AND (S.Close_Date >= DR.StartDate OR S.Close_Date IS NULL)
GROUP BY DR.StartDate
ORDER BY DR.StartDate;
-- Cleanup sample data
DROP TABLE #SampleVals;
示例数据的日期已更改为反映yyyymmdd。我还使用了本地号码表:
CREATE TABLE dbo.Number(n INT NOT NULL IDENTITY) ;
GO
SET NOCOUNT ON ;
INSERT dbo.Number DEFAULT VALUES ;
WHILE SCOPE_IDENTITY() < 5000
INSERT dbo.Number DEFAULT VALUES ;
我几乎没有发布这个,因为Norla在我完成这个之前完成了它,但是我注意到如果开始日期已经关闭(以及该开始日期的月份),Norla的解决方案会填充Close列。 version填充close_date月份的关闭月份列,我相信这就是你要求的。
答案 1 :(得分:0)
我稍微更改了日期,因为我使用的是不同的日期系统,但这应该有效。如果有,请接受!
DECLARE @TABLE1 TABLE
(
ID INT
, Open_date DATETIME
, Close_date DATETIME
)
INSERT INTO @TABLE1 (ID, Open_date, Close_date)
SELECT 1, '01-01-2010', '03-01-2010'
UNION SELECT 2, '01-21-2011', '02-12-2011'
UNION SELECT 3, '03-01-2010', NULL
UNION SELECT 4, '01-10-2010', NULL
DECLARE @MIN_DATE DATETIME
DECLARE @MAX_DATE DATETIME
SELECT @MIN_DATE = MIN(d)
, @MAX_DATE = MAX(d)
FROM
(
SELECT Open_date AS d
FROM @TABLE1
UNION
SELECT Close_date AS d
FROM @TABLE1
)a
--SELECT @MIN_DATE, @MAX_DATE
DECLARE @DATES TABLE
(
ID INT IDENTITY(1,1)
, [date] DATETIME
)
DECLARE @DATE DATETIME
SET @DATE = @MIN_DATE
WHILE (@DATE <= @MAX_DATE)
BEGIN
INSERT INTO @DATES ([date])
VALUES (@DATE)
SET @DATE = @DATE + 1
END
--SELECT *
--FROM @DATES
SELECT MONTH(a.[date]) AS [Month]
, YEAR(a.[date]) AS [Year]
, SUM(CASE WHEN b.Open_date IS NOT NULL THEN 1 ELSE 0 END) AS [Open]
, SUM(CASE WHEN b.Close_date IS NOT NULL THEN 1 ELSE 0 END) AS [Close]
FROM @DATES a
LEFT JOIN @TABLE1 b
ON a.[date] = b.Open_date
GROUP BY YEAR(a.[date]), MONTH(a.[date])
ORDER BY YEAR(a.[date]), MONTH(a.[date])
答案 2 :(得分:0)
对于SQL Server 2005+,您可以尝试
somewhat simpler approach. Try this:
WITH CTE AS
(
SELECT MIN(CONVERT(VARCHAR(6),Dates,112)) YearMonth,
MAX(CONVERT(VARCHAR(6),Dates,112)) MaxDate
FROM ( SELECT Open_Date Dates FROM YourTable
UNION
SELECT Close_Date FROM YourTable) A
UNION ALL
SELECT CONVERT(VARCHAR(6),DATEADD(MONTH,1,YearMonth+'01'),112), MaxDate
FROM CTE
WHERE CONVERT(VARCHAR(6),DATEADD(MONTH,1,YearMonth+'01'),112)<=MaxDate
)
SELECT RIGHT(A.YearMonth,2) [Month], LEFT(A.YearMonth,4) [Year],
COUNT(B.Id) [Open], COUNT(C.Id) [Close]
FROM CTE A
LEFT JOIN YourTable B
ON A.YearMonth = CONVERT(VARCHAR(6),B.Open_Date,112)
LEFT JOIN YourTable C
ON A.YearMonth = CONVERT(VARCHAR(6),C.Close_Date,112)
GROUP BY RIGHT(A.YearMonth,2), LEFT(A.YearMonth,4)
ORDER BY LEFT(A.YearMonth,4), RIGHT(A.YearMonth,2)
答案 3 :(得分:0)
另一个版本
;with T(monthstart, monthend, _tempmax) as (
select
min(Open_date), dateadd(day, -1, dateadd(month, 1, min(Open_date))), dateadd(month, 1, max(Open_date)) as _tempmax from THETABLE
union all
select
dateadd(month, 1, monthstart), dateadd(day, -1, dateadd(month, 2, monthstart)), _tempmax
from T
where dateadd(month, 1, monthstart) <= _tempmax
)
select
month(monthstart) as [month],
year(monthstart) as [year],
sum(case when Open_date between monthstart and monthend then 1 else 0 end),
sum(case when Close_date between monthstart and monthend then 1 else 0 end)
from T
left join
THETABLE on (Open_date between monthstart and monthend) or (Close_date between monthstart and monthend)
group by
month(monthstart),
year(monthstart)