执行联接时值莫名其妙地乘以 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 CHSRsTotal 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 别名的首字母缩略词而不是 tab1tab2 等,这将是一个巨大的好处,因为它会使查询 更容易阅读,特别是考虑到两个查询中相同的 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