SQL Server 2012 Express 中的另一个 LEFT OUTER JOIN 失败
Yet another LEFT OUTER JOIN fail in SQL Server 2012 Express
我想知道是否有人可以解决我的查询问题。我有一个简单的 table,每月可以节省项目费用。总是有连续 12 个月的价值或储蓄,但第一个月可能会有所不同(例如:从 1 月开始有 12 个月,从 3 月开始有 12 个月,等等)。
我需要一份报告,了解给定年份的所有储蓄(按月)。这意味着对于某些项目的节省,如果开始月份不是 1 月,则该项目的部分节省将落入不同的报告年。
所以我需要一个查询,该查询将 return 当前报告年的所有月份,并且对于项目在该月没有储蓄值的地方有零。
我有一些项目从 7 月开始,我只能收回这 6 个月的价值。也就是说,回到 WITH 日期的左连接不是正确的外部连接。有人可以告诉我哪里出错了吗?
查看下面的代码:
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) 部分有效,returns 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
table如下:
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
这段代码应该可以满足您的需求:
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,
prj.ProjectId as ProjectId,
ISNULL(SUM(a.Saving), 0) as yAxisValue
from d
CROSS JOIN
(
SELECT DISTINCT mes.ProjectId
FROM dbo.sf_SnapshotMonthEndSaving() mes
) as prj
LEFT OUTER JOIN
(
SELECT mes.ProjectId, mes.Saving, mes.SavingMonth
FROM dbo.sf_SnapshotMonthEndSaving() mes
) as a
ON d.d = a.SavingMonth
AND prj.ProjectID = a.ProjectID
group by prj.ProjectId, datename(month, d.d), datepart(mm, d.d)
order by prj.ProjectId, datepart(mm, d.d)
Dang,Laughing Vergil 似乎是一个更快的打字员 =)
无论如何,这个想法几乎是一样的。您的 'error' 是您每个月都加入 dbo.sf_SnapshotMonthEndSaving()
中的所有项目。如果一个适合,则仅返回那个,如果两个适合,它将显示这两个等等......但它不会对每个项目重复。这个应该。
DECLARE @StartDate datetime = '1 jan 2016',
@EndDate datetime = '1 dec 2016'
;WITH d(FirstDayOfMonth) 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
),
RelevantProjects AS
(
SELECT DISTINCT ProjectId
FROM dbo.sf_SnapshotMonthEndSaving() mes
WHERE mes.SavingMonth BETWEEN @StartDate AND @EndDate -- you could also join to d but I think this is faster
),
ProjectsAndDates AS
(
SELECT ProjectID,
FirstDayOfMonth
FROM d
CROSS JOIN RelevantProjects
)
select left(datename(month, d.FirstDayOfMonth), 3) as xAxisValueMon,
datepart(mm, d.FirstDayOfMonth) as xAxisValue,
d.ProjectId as ProjectId,
ISNULL(SUM(mes.Saving), 0) as yAxisValue
from ProjectsAndDates d
LEFT OUTER JOIN [MonthEndSaving] mes -- dbo.sf_SnapshotMonthEndSaving() mes
ON mes.SavingMonth = d.FirstDayOfMonth
AND mes.Project_id = d.ProjectID
group by d.ProjectId, datename(month, d.FirstDayOfMonth), datepart(mm, d.FirstDayOfMonth)
order by d.ProjectId, datepart(mm, d.FirstDayOfMonth)
我想知道是否有人可以解决我的查询问题。我有一个简单的 table,每月可以节省项目费用。总是有连续 12 个月的价值或储蓄,但第一个月可能会有所不同(例如:从 1 月开始有 12 个月,从 3 月开始有 12 个月,等等)。
我需要一份报告,了解给定年份的所有储蓄(按月)。这意味着对于某些项目的节省,如果开始月份不是 1 月,则该项目的部分节省将落入不同的报告年。
所以我需要一个查询,该查询将 return 当前报告年的所有月份,并且对于项目在该月没有储蓄值的地方有零。
我有一些项目从 7 月开始,我只能收回这 6 个月的价值。也就是说,回到 WITH 日期的左连接不是正确的外部连接。有人可以告诉我哪里出错了吗?
查看下面的代码:
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) 部分有效,returns 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
table如下:
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
这段代码应该可以满足您的需求:
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,
prj.ProjectId as ProjectId,
ISNULL(SUM(a.Saving), 0) as yAxisValue
from d
CROSS JOIN
(
SELECT DISTINCT mes.ProjectId
FROM dbo.sf_SnapshotMonthEndSaving() mes
) as prj
LEFT OUTER JOIN
(
SELECT mes.ProjectId, mes.Saving, mes.SavingMonth
FROM dbo.sf_SnapshotMonthEndSaving() mes
) as a
ON d.d = a.SavingMonth
AND prj.ProjectID = a.ProjectID
group by prj.ProjectId, datename(month, d.d), datepart(mm, d.d)
order by prj.ProjectId, datepart(mm, d.d)
Dang,Laughing Vergil 似乎是一个更快的打字员 =)
无论如何,这个想法几乎是一样的。您的 'error' 是您每个月都加入 dbo.sf_SnapshotMonthEndSaving()
中的所有项目。如果一个适合,则仅返回那个,如果两个适合,它将显示这两个等等......但它不会对每个项目重复。这个应该。
DECLARE @StartDate datetime = '1 jan 2016',
@EndDate datetime = '1 dec 2016'
;WITH d(FirstDayOfMonth) 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
),
RelevantProjects AS
(
SELECT DISTINCT ProjectId
FROM dbo.sf_SnapshotMonthEndSaving() mes
WHERE mes.SavingMonth BETWEEN @StartDate AND @EndDate -- you could also join to d but I think this is faster
),
ProjectsAndDates AS
(
SELECT ProjectID,
FirstDayOfMonth
FROM d
CROSS JOIN RelevantProjects
)
select left(datename(month, d.FirstDayOfMonth), 3) as xAxisValueMon,
datepart(mm, d.FirstDayOfMonth) as xAxisValue,
d.ProjectId as ProjectId,
ISNULL(SUM(mes.Saving), 0) as yAxisValue
from ProjectsAndDates d
LEFT OUTER JOIN [MonthEndSaving] mes -- dbo.sf_SnapshotMonthEndSaving() mes
ON mes.SavingMonth = d.FirstDayOfMonth
AND mes.Project_id = d.ProjectID
group by d.ProjectId, datename(month, d.FirstDayOfMonth), datepart(mm, d.FirstDayOfMonth)
order by d.ProjectId, datepart(mm, d.FirstDayOfMonth)