所以我开始构建一个查询,将5个单独的表连接在一起,以获取乘法和求和的值。但是,我似乎面临着一个相当奇怪的问题。每当我尝试将某个表连接到我的查询时,突然我的所有值都乘以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
导致问题的表是tblMaterialsUsed
。
感谢您的帮助。
答案 0 :(得分:1)
您的JOIN
条件不足,导致一行加入多行。
如果以下查询产生两个不同的数字,那么您应该知道JOIN
应该受到指责:
SELECT COUNT(*),COUNT(DISTINCT [CHSR #])
FROM Facilities.tblMaterialUsed
然后,您需要先确定如何通过添加JOIN
条件或者首先在子查询中聚合来排除额外记录。
<强>更新强>:
要首先聚合,您可以使用cte
或子查询按CHSR #
聚合,然后加入到该cte /子查询:
;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
答案 1 :(得分:0)
如果添加JOIN会使GROUP BY操作的结果相乘,则JOIN每个JOIN条件返回的行数超过1行。要么缩小它(可能你缺少一个或多个JOIN字段?)或者在GROUP BY中添加更多字段来改变聚合内容的粒度。
问题是每个[CHSR #]
都有一个材料用户列表。这些行导致“笛卡尔积”,使tblMaterialUsed
中每行的其他行重复。因此,当Material Cost
和Number of CHSRs
成倍增加时,总Total Labor Cost
字段可能是正确的。从本质上讲,您需要以相同的粒度级别对数据进行分组,这意味着CHSRNumber
/ [CHSR #]
以下内容应解决此问题。如果没有,那将是由于主查询中每CHSRNumber
/ [CHSR #]
行超过1行(每个CHSRNumber
/ {{1加入1行} [CHSR #]
CTE)。在这种情况下,您可以通过为该聚合创建第二个CTE,然后在新的主查询中加入这两个结果,将相同的理论应用于主查询。 (我已经更新了下面的查询以纳入该更改,因为它可能不需要它)
material
如果您想在View中使用它,请使用内联表值函数,方法是在开头添加以下内容:
;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;
和
CREATE FUNCTION GetCosts (@minimumDate DATE, @maximumDate DATE)
RETURNS TABLE
AS RETURN
;
;WITH
此外,如果您使用表别名而不是ORDER BY
,tab1
等首字母缩略词,这将是一个巨大的好处,因为它会使查询更多更容易阅读,特别是考虑到两个查询中的同一个表甚至不是tab2
。
答案 2 :(得分:0)
看来我可以使用子查询来解决这个问题
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