我有一个SQL 2005表,我们称之为Orders,格式为:
OrderID, OrderDate, OrderAmount
1, 25/11/2008, 10
2, 25/11/2008, 2
3, 30/1002008, 5
然后我需要生成一个报告表,显示过去7天内每天的订购金额:
Day, OrderCount, OrderAmount
25/11/2008, 2, 12
26/11/2008, 0, 0
27/11/2008, 0, 0
28/11/2008, 0, 0
29/11/2008, 0, 0
30/11/2008, 1, 5
通常会产生此问题的SQL查询:
select count(*), sum(OrderAmount)
from Orders
where OrderDate>getdate()-7
group by datepart(day,OrderDate)
有一个问题是它会跳过没有订单的日子:
Day, OrderCount, OrderAmount
25/11/2008, 2, 12
30/11/2008, 1, 5
通常情况下,我会使用计数表和外部联接来修复此行,但我真的在寻找更简单或更有效的解决方案。对于报表查询来说,似乎有一个常见的要求,即已经有一些优雅的解决方案可用。
所以:1。可以在不使用计数表的情况下从简单查询中获得此结果吗?
和2.如果不是,我们可以动态创建这个计数表(可靠)吗(我可以使用CTE创建计数表,但递归堆栈将我限制为100行)?
答案 0 :(得分:10)
SQL不是“跳过”日期...因为查询是针对表中实际存在的数据运行的。那么,如果1月14日表中没有DATE,那么为什么SQL会显示结果:)
你需要做的是制作一个临时表,然后加入它。
CREATE TABLE #MyDates ( TargetDate DATETIME )
INSERT INTO #MyDates VALUES CONVERT(DATETIME, CONVERT(VARCHAR, GETDATE() - 0, 101))
INSERT INTO #MyDates VALUES CONVERT(DATETIME, CONVERT(VARCHAR, GETDATE() - 1, 101))
INSERT INTO #MyDates VALUES CONVERT(DATETIME, CONVERT(VARCHAR, GETDATE() - 2, 101))
INSERT INTO #MyDates VALUES CONVERT(DATETIME, CONVERT(VARCHAR, GETDATE() - 3, 101))
INSERT INTO #MyDates VALUES CONVERT(DATETIME, CONVERT(VARCHAR, GETDATE() - 4, 101))
INSERT INTO #MyDates VALUES CONVERT(DATETIME, CONVERT(VARCHAR, GETDATE() - 5, 101))
INSERT INTO #MyDates VALUES CONVERT(DATETIME, CONVERT(VARCHAR, GETDATE() - 6, 101))
INSERT INTO #MyDates VALUES CONVERT(DATETIME, CONVERT(VARCHAR, GETDATE() - 7, 101))
SELECT CONVERT(VARCHAR, TargetDate, 101) AS Date, COUNT(*) AS OrderCount
FROM dbo.Orders INNER JOIN #MyDates ON Orders.Date = #MyDates.TargetDate
GROUP BY blah blah blah (you know the rest)
你去吧!
答案 1 :(得分:2)
我遇到了同样的问题,这就是我解决它的方法:
SELECT datename(DW,nDays) TimelineDays,
Convert(varchar(10), nDays, 101) TimelineDate,
ISNULL(SUM(Counter),0) Totals
FROM (Select GETDATE() AS nDays
union Select GETDATE()-1
union Select GETDATE()-2
union Select GETDATE()-3
union Select GETDATE()-4
union Select GETDATE()-5
union Select GETDATE()-6) AS tDays
Left Join (Select * From tHistory Where Account = 1000) AS History
on (DATEPART(year,nDays) + DATEPART(MONTH,nDays) + DATEPART(day,nDays)) =
(DATEPART(year,RecordDate) + DATEPART(MONTH,RecordDate) + DATEPART(day,RecordDate))
GROUP BY nDays
ORDER BY nDays DESC
输出是:
TimelineDays, TimelineDate, Totals
Tuesday 10/26/2010 0
Monday 10/25/2010 6
Sunday 10/24/2010 3
Saturday 10/23/2010 2
Friday 10/22/2010 0
Thursday 10/21/2010 0
Wednesday 10/20/2010 0
答案 2 :(得分:1)
如果要查看值为零而不是放置以下查询:
select count(*), sum(OrderAmount)
from Orders
where OrderDate>getdate()-7
and sum(OrderAmount) > 0 or sum(OrderAmount) = 0
group by datepart(day,OrderDate)
答案 3 :(得分:0)
根据SQL Server处理临时表的方式,您可以或多或少地轻松安排创建临时表并使用您感兴趣的7(或8个?)日期填充它。然后您可以将其用作计数表。我所知道的方式并不清晰;您只能选择表中存在的数据,或者可以从表或表集中存在的数据派生。如果Orders表中没有表示日期,则无法从Orders表中选择这些日期。
答案 4 :(得分:0)
由于您还希望在其他查询中经常使用此日期表,我建议您将其设为永久表并创建一个作业,以便每年添加一年的新日期。
答案 5 :(得分:0)
CREATE PROCEDURE [dbo].[sp_Myforeach_Date]
-- Add the parameters for the stored procedure here
@SatrtDate as DateTime,
@EndDate as dateTime,
@DatePart as varchar(2),
@OutPutFormat as int
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
Declare @DateList Table
(Date varchar(50))
WHILE @SatrtDate<= @EndDate
BEGIN
INSERT @DateList (Date) values(Convert(varchar,@SatrtDate,@OutPutFormat))
IF Upper(@DatePart)='DD'
SET @SatrtDate= DateAdd(dd,1,@SatrtDate)
IF Upper(@DatePart)='MM'
SET @SatrtDate= DateAdd(mm,1,@SatrtDate)
IF Upper(@DatePart)='YY'
SET @SatrtDate= DateAdd(yy,1,@SatrtDate)
END
SELECT * FROM @DateList
END
只需输入此代码并致电SP即可 以这种方式
exec sp_Myforeach_Date @SatrtDate='03 Jan 2010',@EndDate='03 Mar 2010',@DatePart='dd',@OutPutFormat=106
<强>感谢 * Suvabrata Roy 强> ICRA在线有限公司 加尔各答 *