执行联接时值莫名其妙地乘以 15 的幂?
Values Inexplicably multiplying by a power of 15 when performing a join?
所以我开始构建一个查询,将 5 个单独的 table 连接在一起以获得要相乘和求和的值。但是,我似乎面临一个相当奇怪的问题。每当我尝试将某个 table 加入我的查询时,我的所有值突然都乘以 15,计数、总和等。我试图找出是什么导致了所有这些额外的运行。有什么想法吗?
完整查询
USE Facilities_Database
DECLARE @minimumDate DATE
DECLARE @maximumDate DATE
SET @minimumDate = '2014/12/11'
SET @maximumDate = '2014/12/15'
SELECT tab4.TypeName AS 'Labor Type'
,tab1.Building
,CAST(@minimumDate AS nvarchar(255)) + ' - ' + CAST(@maximumDate AS nvarchar(255)) AS 'Date Range'
,Count(tab1.CHSRNumber) AS 'Number of CHSRs'
,ISNULL(SUM(tab5.[Item Cost] * tab3.[Amount Used]),0) AS 'Total Material Cost'
,ISNULL(SUM(tab2.[Hour Worked] * tab2.[Hourly CHSR Labor Rate]),0) AS 'Total Labor Cost'
FROM [Facilities].[HardwareSupportRequest] tab1
JOIN Facilities.tblCHSRLaborPerCHSR tab2
ON tab1.CHSRNumber = tab2.[CHSR #]
JOIN Facilities.tblMaterialUsed tab3
ON tab1.CHSRNumber = tab3.[CHSR #]
JOIN Facilities.LaborTypes tab4
ON tab2.LaborTypeId = tab4.Id
JOIN Facilities.tblMaterial tab5
ON tab3.MaterialId = tab5.Id
WHERE tab1.ActualCompleteDate BETWEEN @minimumDate AND @maximumDate AND tab4.TypeName IS NOT NULL
GROUP BY tab4.TypeName,Building
ORDER BY Building,tab4.TypeName
工作查询:
USE Facilities_Database
SELECT tab1.Building
,COUNT(*) AS 'CHSR Count'
,SUM(tab2.[Hour Worked] * 40) AS 'Labor Cost'
FROM [Facilities].[HardwareSupportRequest] tab1
INNER JOIN Facilities.tblCHSRLaborPerCHSR tab2 ON
tab1.CHSRNumber = tab2.[CHSR #]
INNER JOIN Facilities.LaborTypes tab3 ON
tab2.LaborTypeId = tab3.Id
--INNER JOIN Facilities.tblMaterialUsed tab4 ON
--tab4.[CHSR #] = tab1.CHSRNumber
--INNER JOIN Facilities.tblMaterial tab5 ON
-- tab4.MaterialId = tab5.Id
WHERE ActualCompleteDate BETWEEN '2014/12/11' AND '2014/12/15'
GROUP BY tab1.Building,tab3.TypeName
导致问题的 table 是 tblMaterialsUsed
。
感谢您的帮助。
如果添加 JOIN 会乘以 GROUP BY 操作的结果,则 JOIN 会根据 JOIN 条件返回多于 1 行。缩小范围(也许您缺少 1 个或多个 JOIN 字段?)或向 GROUP BY 添加更多字段以更改聚合的粒度。
问题是每个 [CHSR #]
都有一个材料用户列表。这些行导致 "Cartesian Product",使得其他行在 tblMaterialUsed
中每行重复一次。因此,当 Number of CHSRs
和 Total Labor Cost
相乘时,总计 Material Cost
字段可能是正确的。本质上,您需要以相同的粒度级别对数据进行分组,这意味着 CHSRNumber
/ [CHSR #]
一对一
以下应该可以解决这个问题。如果不是,那将是由于主查询中每个 CHSRNumber
/ [CHSR #]
超过 1 行(正在与每个 CHSRNumber
/ [=12 的 1 行连接) =] material
CTE)。在这种情况下,您可以通过为该聚合创建第二个 CTE 将相同的理论应用于主查询,然后在新的主查询中加入这两个结果。 (我已经更新了下面的查询以合并该更改,因为我怀疑它不需要)
;WITH material AS
(
SELECT mu.[CHSR #],
ISNULL(SUM(mtrl.[Item Cost] * mu.[Amount Used]),0) AS [MaterialCost]
FROM Facilities.tblMaterialUsed mu
INNER JOIN Facilities.tblMaterial mtrl
ON mu.MaterialId = mtrl.Id
GROUP BY mu.[CHSR #]
), labour AS
(
SELECT tab1.CHSRNumber,
tab4.TypeName,
tab1.Building,
ISNULL(SUM(tab2.[Hour Worked] * tab2.[Hourly CHSR Labor Rate]),0) AS [LaborCost]
FROM [Facilities].[HardwareSupportRequest] tab1
JOIN Facilities.tblCHSRLaborPerCHSR tab2
ON tab1.CHSRNumber = tab2.[CHSR #]
JOIN Facilities.LaborTypes tab4
ON tab2.LaborTypeId = tab4.Id
WHERE tab1.ActualCompleteDate BETWEEN @minimumDate AND @maximumDate
AND tab4.TypeName IS NOT NULL
GROUP BY tab1.CHSRNumber, tab4.TypeName, tab1.Building
)
SELECT labour.TypeName AS [Labor Type],
labour.Building,
CAST(@minimumDate AS NVARCHAR(255)) + ' - '
+ CAST(@maximumDate AS NVARCHAR(255)) AS [Date Range],
COUNT(labour.[CHSRNumber]) AS [Number of CHSRs],
SUM(material.[MaterialCost]) AS [Total Material Cost],
SUM(labour.[LaborCost]) AS [Total Labor Cost]
FROM labour
INNER JOIN material
ON labour.CHSRNumber = material.[CHSR #]
GROUP BY labour.TypeName, labour.Building
ORDER BY labour.Building, labour.TypeName;
如果您希望在视图中使用此功能,请通过在开头添加以下内容来使用内联 Table 值函数:
CREATE FUNCTION GetCosts (@minimumDate DATE, @maximumDate DATE)
RETURNS TABLE
AS RETURN
和
- 删除
;WITH
之前的;
- 删除
ORDER BY
此外,如果您使用 table 别名的首字母缩略词而不是 tab1
、tab2
等,这将是一个巨大的好处,因为它会使查询 更容易阅读,特别是考虑到两个查询中相同的 table 甚至不相同 tab#
.
您的 JOIN
条件不足,导致一行连接到多行。
如果以下查询得到两个不同的数字,那么您就知道 JOIN
是罪魁祸首:
SELECT COUNT(*),COUNT(DISTINCT [CHSR #])
FROM Facilities.tblMaterialUsed
然后您需要确定如何通过添加到您的 JOIN
条件或可能先在子查询中聚合来排除额外记录。
更新:
要首先聚合,您可以使用 cte
或子查询按 CHSR #
聚合,然后加入 cte/subquery:
;WITH Materials AS (SELECT mat.[CHSR #]
,ISNULL(SUM(tab5.[Item Cost] * tab3.[Amount Used]),0) AS Total_Material_Cost
FROM Facilities.tblMaterialUsed tab3
JOIN Facilities.tblMaterial tab5
ON tab3.MaterialId = tab5.Id
GROUP BY mat.[CHSR #]
)
SELECT tab4.TypeName AS 'Labor Type'
,tab1.Building
,CAST(@minimumDate AS nvarchar(255)) + ' - ' + CAST(@maximumDate AS nvarchar(255)) AS 'Date Range'
,Count(tab1.CHSRNumber) AS 'Number of CHSRs'
,SUM(mat.Total_Material_Cost) AS 'Total Material Cost'
,ISNULL(SUM(tab2.[Hour Worked] * tab2.[Hourly CHSR Labor Rate]),0) AS 'Total Labor Cost'
FROM [Facilities].[HardwareSupportRequest] tab1
JOIN Facilities.tblCHSRLaborPerCHSR tab2
ON tab1.CHSRNumber = tab2.[CHSR #]
JOIN Facilities.LaborTypes tab4
ON tab2.LaborTypeId = tab4.Id
JOIN Materials mat
ON tab1.CHSRNumber = mat.[CHSR #]
WHERE tab1.ActualCompleteDate BETWEEN @minimumDate AND @maximumDate AND tab4.TypeName IS NOT NULL
GROUP BY tab4.TypeName,Building
ORDER BY Building,tab4.TypeName
看来我可以使用子查询来解决这个问题
USE Facilities_Database
DECLARE @minimumDate DATE
DECLARE @maximumDate DATE
SET @minimumDate = '2012/12/11'
SET @maximumDate = '2014/12/15'
SELECT LaborTypes.TypeName AS 'Labor Type'
,CHSRs.Building
,CAST(@minimumDate AS nvarchar(255)) + ' - ' + CAST(@maximumDate AS nvarchar(255)) AS 'Date Range'
,Count(CHSRs.CHSRNumber) AS 'Number of CHSRs'
,ISNULL(SUM(matUsed.cost),0) AS 'Total Material Cost'
,ISNULL(SUM(Labor.[Hour Worked] * Labor.[Hourly CHSR Labor Rate]),0) AS 'Total Labor Cost'
FROM [Facilities].[HardwareSupportRequest] CHSRs
JOIN Facilities.tblCHSRLaborPerCHSR Labor
ON CHSRs.CHSRNumber = Labor.[CHSR #]
JOIN (SELECT ROUND(SUM(matU.[Amount Used] * mat.[Item Cost] * 1.05417 * 1.15),2) AS cost, [CHSR #]
FROM Facilities.tblMaterialUsed matU
JOIN Facilities.tblMaterial mat ON
matU.MaterialId = mat.Id
GROUP BY matU.[CHSR #]) matUsed ON
matUsed.[CHSR #] = CHSRs.CHSRNumber
--JOIN Facilities.tblMaterialUsed tab3
-- ON CHSRs.CHSRNumber = tab3.[CHSR #]
JOIN Facilities.LaborTypes LaborTypes
ON Labor.LaborTypeId = LaborTypes.Id
--JOIN Facilities.tblMaterial tab5
-- ON tab3.MaterialId = tab5.Id
WHERE CHSRs.ActualCompleteDate BETWEEN @minimumDate AND @maximumDate AND LaborTypes.TypeName IS NOT NULL
GROUP BY LaborTypes.TypeName,Building
ORDER BY Building,LaborTypes.TypeName
所以我开始构建一个查询,将 5 个单独的 table 连接在一起以获得要相乘和求和的值。但是,我似乎面临一个相当奇怪的问题。每当我尝试将某个 table 加入我的查询时,我的所有值突然都乘以 15,计数、总和等。我试图找出是什么导致了所有这些额外的运行。有什么想法吗?
完整查询
USE Facilities_Database
DECLARE @minimumDate DATE
DECLARE @maximumDate DATE
SET @minimumDate = '2014/12/11'
SET @maximumDate = '2014/12/15'
SELECT tab4.TypeName AS 'Labor Type'
,tab1.Building
,CAST(@minimumDate AS nvarchar(255)) + ' - ' + CAST(@maximumDate AS nvarchar(255)) AS 'Date Range'
,Count(tab1.CHSRNumber) AS 'Number of CHSRs'
,ISNULL(SUM(tab5.[Item Cost] * tab3.[Amount Used]),0) AS 'Total Material Cost'
,ISNULL(SUM(tab2.[Hour Worked] * tab2.[Hourly CHSR Labor Rate]),0) AS 'Total Labor Cost'
FROM [Facilities].[HardwareSupportRequest] tab1
JOIN Facilities.tblCHSRLaborPerCHSR tab2
ON tab1.CHSRNumber = tab2.[CHSR #]
JOIN Facilities.tblMaterialUsed tab3
ON tab1.CHSRNumber = tab3.[CHSR #]
JOIN Facilities.LaborTypes tab4
ON tab2.LaborTypeId = tab4.Id
JOIN Facilities.tblMaterial tab5
ON tab3.MaterialId = tab5.Id
WHERE tab1.ActualCompleteDate BETWEEN @minimumDate AND @maximumDate AND tab4.TypeName IS NOT NULL
GROUP BY tab4.TypeName,Building
ORDER BY Building,tab4.TypeName
工作查询:
USE Facilities_Database
SELECT tab1.Building
,COUNT(*) AS 'CHSR Count'
,SUM(tab2.[Hour Worked] * 40) AS 'Labor Cost'
FROM [Facilities].[HardwareSupportRequest] tab1
INNER JOIN Facilities.tblCHSRLaborPerCHSR tab2 ON
tab1.CHSRNumber = tab2.[CHSR #]
INNER JOIN Facilities.LaborTypes tab3 ON
tab2.LaborTypeId = tab3.Id
--INNER JOIN Facilities.tblMaterialUsed tab4 ON
--tab4.[CHSR #] = tab1.CHSRNumber
--INNER JOIN Facilities.tblMaterial tab5 ON
-- tab4.MaterialId = tab5.Id
WHERE ActualCompleteDate BETWEEN '2014/12/11' AND '2014/12/15'
GROUP BY tab1.Building,tab3.TypeName
导致问题的 table 是 tblMaterialsUsed
。
感谢您的帮助。
如果添加 JOIN 会乘以 GROUP BY 操作的结果,则 JOIN 会根据 JOIN 条件返回多于 1 行。缩小范围(也许您缺少 1 个或多个 JOIN 字段?)或向 GROUP BY 添加更多字段以更改聚合的粒度。
问题是每个 [CHSR #]
都有一个材料用户列表。这些行导致 "Cartesian Product",使得其他行在 tblMaterialUsed
中每行重复一次。因此,当 Number of CHSRs
和 Total Labor Cost
相乘时,总计 Material Cost
字段可能是正确的。本质上,您需要以相同的粒度级别对数据进行分组,这意味着 CHSRNumber
/ [CHSR #]
以下应该可以解决这个问题。如果不是,那将是由于主查询中每个 CHSRNumber
/ [CHSR #]
超过 1 行(正在与每个 CHSRNumber
/ [=12 的 1 行连接) =] material
CTE)。在这种情况下,您可以通过为该聚合创建第二个 CTE 将相同的理论应用于主查询,然后在新的主查询中加入这两个结果。 (我已经更新了下面的查询以合并该更改,因为我怀疑它不需要)
;WITH material AS
(
SELECT mu.[CHSR #],
ISNULL(SUM(mtrl.[Item Cost] * mu.[Amount Used]),0) AS [MaterialCost]
FROM Facilities.tblMaterialUsed mu
INNER JOIN Facilities.tblMaterial mtrl
ON mu.MaterialId = mtrl.Id
GROUP BY mu.[CHSR #]
), labour AS
(
SELECT tab1.CHSRNumber,
tab4.TypeName,
tab1.Building,
ISNULL(SUM(tab2.[Hour Worked] * tab2.[Hourly CHSR Labor Rate]),0) AS [LaborCost]
FROM [Facilities].[HardwareSupportRequest] tab1
JOIN Facilities.tblCHSRLaborPerCHSR tab2
ON tab1.CHSRNumber = tab2.[CHSR #]
JOIN Facilities.LaborTypes tab4
ON tab2.LaborTypeId = tab4.Id
WHERE tab1.ActualCompleteDate BETWEEN @minimumDate AND @maximumDate
AND tab4.TypeName IS NOT NULL
GROUP BY tab1.CHSRNumber, tab4.TypeName, tab1.Building
)
SELECT labour.TypeName AS [Labor Type],
labour.Building,
CAST(@minimumDate AS NVARCHAR(255)) + ' - '
+ CAST(@maximumDate AS NVARCHAR(255)) AS [Date Range],
COUNT(labour.[CHSRNumber]) AS [Number of CHSRs],
SUM(material.[MaterialCost]) AS [Total Material Cost],
SUM(labour.[LaborCost]) AS [Total Labor Cost]
FROM labour
INNER JOIN material
ON labour.CHSRNumber = material.[CHSR #]
GROUP BY labour.TypeName, labour.Building
ORDER BY labour.Building, labour.TypeName;
如果您希望在视图中使用此功能,请通过在开头添加以下内容来使用内联 Table 值函数:
CREATE FUNCTION GetCosts (@minimumDate DATE, @maximumDate DATE)
RETURNS TABLE
AS RETURN
和
- 删除
;WITH
之前的 - 删除
ORDER BY
;
此外,如果您使用 table 别名的首字母缩略词而不是 tab1
、tab2
等,这将是一个巨大的好处,因为它会使查询 更容易阅读,特别是考虑到两个查询中相同的 table 甚至不相同 tab#
.
您的 JOIN
条件不足,导致一行连接到多行。
如果以下查询得到两个不同的数字,那么您就知道 JOIN
是罪魁祸首:
SELECT COUNT(*),COUNT(DISTINCT [CHSR #])
FROM Facilities.tblMaterialUsed
然后您需要确定如何通过添加到您的 JOIN
条件或可能先在子查询中聚合来排除额外记录。
更新:
要首先聚合,您可以使用 cte
或子查询按 CHSR #
聚合,然后加入 cte/subquery:
;WITH Materials AS (SELECT mat.[CHSR #]
,ISNULL(SUM(tab5.[Item Cost] * tab3.[Amount Used]),0) AS Total_Material_Cost
FROM Facilities.tblMaterialUsed tab3
JOIN Facilities.tblMaterial tab5
ON tab3.MaterialId = tab5.Id
GROUP BY mat.[CHSR #]
)
SELECT tab4.TypeName AS 'Labor Type'
,tab1.Building
,CAST(@minimumDate AS nvarchar(255)) + ' - ' + CAST(@maximumDate AS nvarchar(255)) AS 'Date Range'
,Count(tab1.CHSRNumber) AS 'Number of CHSRs'
,SUM(mat.Total_Material_Cost) AS 'Total Material Cost'
,ISNULL(SUM(tab2.[Hour Worked] * tab2.[Hourly CHSR Labor Rate]),0) AS 'Total Labor Cost'
FROM [Facilities].[HardwareSupportRequest] tab1
JOIN Facilities.tblCHSRLaborPerCHSR tab2
ON tab1.CHSRNumber = tab2.[CHSR #]
JOIN Facilities.LaborTypes tab4
ON tab2.LaborTypeId = tab4.Id
JOIN Materials mat
ON tab1.CHSRNumber = mat.[CHSR #]
WHERE tab1.ActualCompleteDate BETWEEN @minimumDate AND @maximumDate AND tab4.TypeName IS NOT NULL
GROUP BY tab4.TypeName,Building
ORDER BY Building,tab4.TypeName
看来我可以使用子查询来解决这个问题
USE Facilities_Database
DECLARE @minimumDate DATE
DECLARE @maximumDate DATE
SET @minimumDate = '2012/12/11'
SET @maximumDate = '2014/12/15'
SELECT LaborTypes.TypeName AS 'Labor Type'
,CHSRs.Building
,CAST(@minimumDate AS nvarchar(255)) + ' - ' + CAST(@maximumDate AS nvarchar(255)) AS 'Date Range'
,Count(CHSRs.CHSRNumber) AS 'Number of CHSRs'
,ISNULL(SUM(matUsed.cost),0) AS 'Total Material Cost'
,ISNULL(SUM(Labor.[Hour Worked] * Labor.[Hourly CHSR Labor Rate]),0) AS 'Total Labor Cost'
FROM [Facilities].[HardwareSupportRequest] CHSRs
JOIN Facilities.tblCHSRLaborPerCHSR Labor
ON CHSRs.CHSRNumber = Labor.[CHSR #]
JOIN (SELECT ROUND(SUM(matU.[Amount Used] * mat.[Item Cost] * 1.05417 * 1.15),2) AS cost, [CHSR #]
FROM Facilities.tblMaterialUsed matU
JOIN Facilities.tblMaterial mat ON
matU.MaterialId = mat.Id
GROUP BY matU.[CHSR #]) matUsed ON
matUsed.[CHSR #] = CHSRs.CHSRNumber
--JOIN Facilities.tblMaterialUsed tab3
-- ON CHSRs.CHSRNumber = tab3.[CHSR #]
JOIN Facilities.LaborTypes LaborTypes
ON Labor.LaborTypeId = LaborTypes.Id
--JOIN Facilities.tblMaterial tab5
-- ON tab3.MaterialId = tab5.Id
WHERE CHSRs.ActualCompleteDate BETWEEN @minimumDate AND @maximumDate AND LaborTypes.TypeName IS NOT NULL
GROUP BY LaborTypes.TypeName,Building
ORDER BY Building,LaborTypes.TypeName