【发布时间】:2016-12-20 19:57:55
【问题描述】:
我想知道是否有人能够解决我的查询问题。我有一个简单的表格,每个月都有项目节省。总有连续 12 个月的价值或储蓄,但第一个月可能会有所不同(例如:从 1 月开始持续 12 个月,从 3 月开始持续 12 个月等)。
我需要一份报告,以获取给定年份的所有储蓄(按月)。这意味着,对于某些项目节约而言,如果开始月份不是 1 月,那么部分项目节约将落在不同的报告年度。
因此,我需要一个查询,该查询将返回当前报告年度的所有月份,并且对于项目在该月没有保存值的情况为零。
我有一些从 7 月开始的项目,而我只拿回这 6 个月的价值。也就是说,回到日期的左连接不是正确的外部连接。谁能告诉我哪里出错了?
见下面的代码:
DECLARE @MonthEndSnapshot SMALLDATETIME;
SELECT @MonthEndSnapshot = getdate()
DECLARE @StartDate SMALLDATETIME, @EndDate SMALLDATETIME;
SELECT @StartDate = FORMAT(@MonthEndSnapshot, 'yyyy') + '0101', @EndDate = FORMAT(@MonthEndSnapshot, 'yyyy') + '1231';
;WITH d(d) AS
(
SELECT
DATEADD(MONTH, n, DATEADD(MONTH, DATEDIFF(MONTH, 0, @StartDate), 0))
FROM
(SELECT TOP
(DATEDIFF(MONTH, @StartDate, @EndDate) + 1)
n = ROW_NUMBER() OVER (ORDER BY [object_id]) - 1
FROM
sys.all_objects
ORDER BY [object_id]) AS n
)
select
left(datename(month, d.d), 3) as xAxisValueMon,
datepart(mm, d.d) as xAxisValue,
a.ProjectId as ProjectId,
ISNULL(SUM(a.Saving), 0) as yAxisValue
from
d
LEFT OUTER JOIN
(SELECT
mes.ProjectId, mes.Saving, mes.SavingMonth
FROM
dbo.sf_SnapshotMonthEndSaving() mes) AS a ON d.d = a.SavingMonth
group by
a.ProjectId, datename(month, d.d), datepart(mm, d.d)
order by
a.ProjectId, datepart(mm, d.d)
WITH d(d) 部分有效,并返回 12 个月的日期(从 1 月到 12 月的第 1 个月)。
我还尝试了以下结构作为查询:
;WITH d(d) AS
(
SELECT DATEADD(MONTH, n, DATEADD(MONTH, DATEDIFF(MONTH, 0, @StartDate), 0))
FROM ( SELECT TOP (DATEDIFF(MONTH, @StartDate, @EndDate) + 1)
n = ROW_NUMBER() OVER (ORDER BY [object_id]) - 1
FROM sys.all_objects ORDER BY [object_id] ) AS n
)
select left(datename(month, d.d), 3) as xAxisValueMon,
datepart(mm, d.d) as xAxisValue,
mes.ProjectId as ProjectId,
ISNULL(SUM(mes.Saving), 0) as yAxisValue
from d LEFT OUTER JOIN
dbo.sf_SnapshotMonthEndSaving() mes
ON d.d = mes.SavingMonth
group by mes.ProjectId, datename(month, d.d), datepart(mm, d.d)
order by mes.ProjectId, datepart(mm, d.d)
但结果相同。 MonthEndSaving表如下:
CREATE TABLE [dbo].[MonthEndSaving]
(
[MonthEndSavingId] [int] IDENTITY(1,1) NOT NULL,
[MonthEndSnapshot] [datetime] NOT NULL,
[ProjectId] [int] NOT NULL,
[SavingMonth] [datetime] NOT NULL,
[Saving] [money] NOT NULL,
[DateCreated] [datetime] NOT NULL,
PRIMARY KEY CLUSTERED (MonthEndSavingId)
)
GO
ALTER TABLE MonthEndSaving
ADD CONSTRAINT [ProjectMonthEndSaving]
FOREIGN KEY (ProjectId) REFERENCES [dbo].[Project](ProjectId)
GO
【问题讨论】:
-
mes.SavingMonth带来了什么价值?? -
projectID 只会在该项目的
SavingMonth值与您的d集合中的月份匹配的月份显示。如果您希望每个项目 ID 都显示出来,则必须无条件地加入它们。如果我理解正确(例如ISNULL(SUM(CASE WHEN mes.SavingMonth = MONTH(d.d) THEN mes.Saving ELSE 0 END),0)),您的情况需要在SUM内的CASE语句中。 -
只关注一个 ProjectId(从 7 月开始保存),您预计会获得 12 条记录:一条用于 1 月,一条用于 2 月,一条用于 3 月,等等……您希望这些记录是第一个6 条记录的金额为零,第 7 条及以后的记录有来自表函数的相关金额。对?问题是您只能获得 6 条记录:7 月的一条,8 月的一条,9 月的一条等。每条记录都有各自的金额。我理解正确吗?
-
感谢您的回复,但这似乎不起作用。所以 SavingMonth 是一个日期,所以我将您的代码行固定为:
-
@marc_s ...啊你一定是风格的警察!是的,我确实坚持一种风格,但在这种情况下,我将代码传递给了决定不这样做的人。目前,我的首要任务是让它工作,而不是担心整理它。但感谢您的宝贵意见。
标签: sql sql-server join outer-join