例如,我有一张订单表。该表有一个键(Order.No),一个打开订单的日期(Order.Open)和一个订单关闭的日期(Order.Close)。
No Open Close --------- ---------- ---------- 2013-1208 2013-03-11 2013-03-26 2013-1272 2013-03-11 2013-03-11 2013-1273 2013-03-11 2013-03-11 2013-1274 2013-03-11 2013-03-11 2013-1275 2013-03-11 2013-03-11 2013-1280 2013-03-11 2013-06-26 2013-1281 2013-03-11 2013-04-18 2013-1282 2013-03-11 2013-03-14 2013-1287 2013-03-12 2013-04-18 2013-1291 2013-03-12 2013-03-12
现在我想进行查询,在那里我可以找到每月有多少订单在本月的最后一天仍然开放。
例如,我想了解1月最后一天仍有多少订单仍在营业:
订单在2月的第一天或之后关闭,订单在2月的第一天之前开放:
SELECT COUNT(Order.No) 'Open', '1' 'Month', '2013' 'Year' FROM Orders
WHERE (Orders.Open < '2013-02-01') AND (Orders.Close >= '2013-02-01')
现在,如果我想获得每个月的这些信息,我将不得不这样做:
SELECT COUNT(Order.No) 'Open', '1' 'Month', '2013' 'Year' FROM Orders
WHERE (Orders.Open < '2013-02-01') AND (Orders.Close >= '2013-02-01')
UNION
SELECT COUNT(Order.No) Open, '2' Month, '2013' 'Year' FROM Orders
WHERE (Orders.Open < '2013-03-01') AND (Orders.Close >= '2013-03-01')
UNION
SELECT COUNT(Order.No) 'Open', '3' 'Month', '2013' 'Year' FROM Orders
WHERE (Orders.Open < '2013-04-01') AND (Orders.Close >= '2013-04-01')
UNION
SELECT COUNT(Order.No) 'Open', '4' Month, '2013' Year FROM Orders
WHERE (Orders.Open < '2013-05-01') AND (Orders.Close >= '2013-05-01')
我可以以某种方式简化此查询,因此我不必每个月和每年都写这个吗?
所需的输出类似于:
Open Month Year ---- ----- ---- 684 1 2013 683 2 2013 760 3 2013 659 4 2013
答案 0 :(得分:3)
首先生成您希望在结果中看到的所有月份。然后每个月加入未结订单并按月计算。
with months as
(
select
datefromparts(year(min(opened)), month(min(opened)), 1) as startdate
from orders
union all
select
dateadd(month, 1, startdate)
from months
where dateadd(month, 1, startdate) <= cast(getdate() as date)
)
select
year(months.startdate) as yr, month(months.startdate) as mon, count(orders.opened) as cnt
from months
left join orders
on orders.opened <= eomonth(months.startdate)
and coalesce(orders.closed, '2999-12-31') > eomonth(months.startdate)
group by year(months.startdate), month(months.startdate)
order by year(months.startdate), month(months.startdate);
这是SQL小提琴:http://sqlfiddle.com/#!6/12ee7/3。
在SQL Server 2008中,缺少函数DATEFROMPARTS和EOMONTH。替换为
cast( cast(year(min(opened)) as varchar) + '-' + cast(month(min(opened)) as varchar) + '-01' as date) as startdate
和
dateadd(day, -1, dateadd(month, 1, months.startdate))
以下是SQL Server 2008的SQL小提琴:http://sqlfiddle.com/#!3/12ee7/5。
答案 1 :(得分:2)
您只需输入所需的月份/年份列表并加入其中,例如
SELECT [Open] = COUNT(o.No),
[Month] = DATEPART(MONTH, d.[Date]),
[Year] = DATEPART(YEAR, d.[Date])
FROM (VALUES
('2013-01-01'),
('2013-02-01'),
('2013-03-01'),
('2013-04-01'),
('2013-05-01'),
('2013-06-01')
) d (Date)
LEFT JOIN Orders AS o
ON o.[Open] < d.[Date]
AND o.[Close] >= d.[Date]
GROUP BY d.Date;
如果您有calendar table,则可以使用此代码而不是硬编码日期列表。
如果您不想对所需日期进行硬编码,那么您可以相当轻松地生成列表,首先生成一个数字列表:
WITH E1 AS -- 10 ROWS
( SELECT N = 1
FROM (VALUES (1), (1), (1), (1), (1), (1), (1), (1), (1), (1)) n (N)
), E2 AS -- 10 X 10 = 100 ROWS
( SELECT N = 1
FROM E1 CROSS JOIN E1 AS E2
), E3 AS -- 100 x 100 = 10,000 ROWS
( SELECT N = 1
FROM E2 CROSS JOIN E2 AS E3
)
SELECT N = ROW_NUMBER() OVER(ORDER BY N)
FROM E3;
这只是一个例子,但是会产生10,000个连续数字,实际上你可能不需要报告10,000个月,但要证明它并没有什么坏处。然后,您可以将此数字列表转换为日期列表:
WITH E1 (N) AS
( SELECT 1
FROM (VALUES (1), (1), (1), (1), (1), (1), (1), (1), (1), (1)) n (N)
),
E2 (N) AS (SELECT 1 FROM E1 CROSS JOIN E1 AS E2),
E3 (N) AS (SELECT 1 FROM E2 CROSS JOIN E2 AS E3)
SELECT [Date] = DATEADD(MONTH, ROW_NUMBER() OVER(ORDER BY N) - 1, '19000101')
FROM E3;
然后你可以将它用作主表并左键加入订单:
WITH E1 (N) AS
( SELECT 1
FROM (VALUES (1), (1), (1), (1), (1), (1), (1), (1), (1), (1)) n (N)
),
E2 (N) AS (SELECT 1 FROM E1 CROSS JOIN E1 AS E2),
E3 (N) AS (SELECT 1 FROM E2 CROSS JOIN E2 AS E3),
Dates AS
( SELECT [Date] = DATEADD(MONTH, ROW_NUMBER() OVER(ORDER BY N) - 1, '19000101')
FROM E3
)
SELECT [Open] = COUNT(o.No),
[Month] = DATEPART(MONTH, d.[Date]),
[Year] = DATEPART(YEAR, d.[Date])
FROM Dates AS d
LEFT JOIN Orders AS o
ON o.[Open] < d.[Date]
AND o.[Close] >= d.[Date]
WHERE d.Date >= '20130101' -- OR WHATEVER DATE YOU LIKE
AND d.Date < GETDATE();
关于生成和使用数字/日期表的一些进一步阅读,无论是静态还是动态,请看一下这个系列:
答案 2 :(得分:2)
也试试这个。 您可以更改条件以获得更好的结果
SELECT COUNT(`no`) Open,
DATE_FORMAT(`open`,'%Y-%m') as period,
month(`open`) Month,
year(`open`) Year
FROM `orders`
WHERE DATE_FORMAT(`close`, '%Y-%m') <> period
GROUP BY period
答案 3 :(得分:1)
SELECT COUNT(Order.No) Open, '1' Month, '2013' Year FROM Orders
group by Orders.Open, Orders.Close
答案 4 :(得分:1)
试试这个
SELECT DISTINCT COUNT(no) OVER (PARTITION BY DATEPART(mm,Open)) AS [Open]
DATEPART(mm,Open) AS [Month],
DATEPART(mm,Open) AS [Year]
FROM dbo.tble
答案 5 :(得分:1)
首先,创建一个月份系列,以便您的结果集中没有任何空白。然后根据所需条件将其加入您的订单表。
按月份系列对结果进行分组并完成。
;with months as (
select cast('2013-01-01' as datetime) as dt union all
select cast('2013-02-01' as datetime) union all
select cast('2013-03-01' as datetime) union all
select cast('2013-04-01' as datetime) union all
select cast('2013-05-01' as datetime) union all
select cast('2013-06-01' as datetime) union all
select cast('2013-07-01' as datetime) union all
select cast('2013-08-01' as datetime) union all
select cast('2013-09-01' as datetime) union all
select cast('2013-10-01' as datetime) union all
select cast('2013-11-01' as datetime) union all
select cast('2013-12-01' as datetime)
)
select count(o.No), datepart(month, m.dt) month, datepart(year, m.dt) year
from months m
left join Orders o
on o.Open < dateadd(month, m.dt, 1)
and o.Close >= dateadd(month, m.dt, 1)
group by m.dt
答案 6 :(得分:0)
Jt,请看,这是否有效。
让@Order
成为表格。
DECLARE @Order TABLE (No VARCHAR(20),[OPEN] Date,[Close] Date)
SELECT YEAR([OPEN]),
MONTH([OPEN]),
SUM(IIF([Close] > DATEADD(DAY, 1,EOMONTH([OPEN])),1,0))
FROM @Order
GROUP BY YEAR([OPEN]),MONTH([OPEN])