【问题标题】:Why do I have duplicate records in my JOIN为什么我的 JOIN 中有重复记录
【发布时间】:2016-08-25 14:54:41
【问题描述】:

我正在从表 ProductionReportMetrics 中检索数据,其中我有列 NetRate_QuoteID。然后到那个结果集我需要得到Description 列。

为了获得Description 列,我需要加入 3 个表:

  • NetRate_Quote_Insur_Quote
  • NetRate_Quote_Insur_Quote_Locat
  • NetRate_Quote_Insur_Quote_Locat_Liabi

但在那之后,我的保费就完全关闭了。

我在这里做错了什么?

SELECT QLL.Description,
       QLL.ClassCode,
       prm.NetRate_QuoteID,
       QL.LocationID,
       ISNULL(SUM(premium),0) AS NetWrittenPremium,
       MONTH(prm.EffectiveDate) AS EffMonth
FROM ProductionReportMetrics prm    
LEFT JOIN NetRate_Quote_Insur_Quote Q
    ON prm.NetRate_QuoteID = Q.QuoteID
INNER JOIN NetRate_Quote_Insur_Quote_Locat QL
    ON Q.QuoteID = QL.QuoteID
INNER JOIN NetRate_Quote_Insur_Quote_Locat_Liabi QLL
    ON QL.LocationID = QLL.LocationID       
WHERE YEAR(prm.EffectiveDate) = 2016 AND
      CompanyLine = 'Ironshore Insurance Company' 
GROUP BY MONTH(prm.EffectiveDate),
         QLL.Description,
         QLL.ClassCode,
         prm.NetRate_QuoteID,
         QL.LocationID 

我认为这个表的问题:

我在这个查询中遗漏了什么?

select 
        ClassCode,
        QLL.Description,
        sum(Premium)

from    ProductionReportMetrics prm
LEFT JOIN  NetRate_Quote_Insur_Quote Q ON prm.NetRate_QuoteID = Q.QuoteID
LEFT JOIN NetRate_Quote_Insur_Quote_Locat QL ON Q.QuoteID = QL.QuoteID  
LEFT JOIN
            (SELECT * FROM NetRate_Quote_Insur_Quote_Locat_Liabi nqI 
                JOIN ( SELECT LocationID, MAX(ClassCode) 
                FROM NetRate_Quote_Insur_Quote_Locat_Liabi GROUP BY LocationID ) nqA 
                    ON nqA.LocationID = nqI.LocationID ) QLL ON QLL.LocationID = QL.LocationID  
where   Year(prm.EffectiveDate) = 2016 AND CompanyLine = 'Ironshore Insurance Company' 
GROUP BY Q.QuoteID,QL.QuoteID,QL.LocationID

现在它说

Msg 8156, Level 16, State 1, Line 14
The column 'LocationID' was specified multiple times for 'QLL'.

【问题讨论】:

  • 几个问题:为什么在第一次连接时使用了左连接?您的列 premium、CompanyLine 属于哪些表?
  • 在此示例结果集中,任何地方都没有重复项。例如,如果您希望只有一条记录为 Contractors - Executive Supervisors, 91580+,那么您将不得不以某种方式聚合这些记录中的其他列(例如,使用平均值、最大值、最小值等)。
  • 我使用 LEFT JOIN 是因为我想保留 ProductionReportMetrics 表中的结果,然后,我想在该结果中添加 ClassCode Description 列。因此,根据 LEFT JOIN 规则,它保留左表中的所有记录并连接右表中的记录。 Premium 和 CompanyLine 列属于 ProductionReportMetrics 表。我也尝试使用 INNER JOIN,但结果相同。
  • 蒂姆,你是说没有重复,因为 NetRate_QuoteID 列是唯一的吗?如果我只是检索SUM(Premium) from ProductionReportMetrics,我得到了 11,000,000 美元。但是在我完成这些加入之后,我的保费要高得多。我不明白为什么
  • 你的表之间的连接是什么关系?他们都是一对一的吗?如果这些连接中的任何一个是一对多的,那么您可能会在那里创建一个副本。

标签: sql-server tsql join reporting-services


【解决方案1】:

看起来 DVT 基本上找到了答案。由于连接而获得不同数量(即重复行)的唯一原因是其中一个连接表与主表不是 1:1 关系。
我建议您对这些表进行快速检查,查找表数。

    --this should be your baseline count
    SELECT COUNT(*)
    FROM ProductionReportMetrics
    GROUP BY MONTH(prm.EffectiveDate),
        prm.NetRate_QuoteID

    --this will be a check against the first joined table.  
    SELECT COUNT(*)
    FROM NetRate_Quote_Insur_Quote Q
    WHERE QuoteID IN
        (SELECT NetRate_QuoteID 
            FROM ProductionReportMetrics
            GROUP BY MONTH(prm.EffectiveDate),
                prm.NetRate_QuoteID)

基本上,您需要对每个连接的表进行类似的检查。如果任何连接的表是分组语句的一部分,请确保它们也在计数检查语句的分组中。还要确保更改检查计数语句的 WHERE 子句以使用您正在使用的连接子句列。
一旦您找到一个返回错误行数的表,您就会知道是哪个表导致了问题。然后,您只需决定如何将该表限制为不同的行(某种类型的聚合)。
这个建议实际上只是为了向您展示如何对这个特定的查询进行 QA。把它分解成尽可能小的部分。在这种情况下,我们知道是一个连接导致了问题,所以一次一个连接,直到找到违规者。

【讨论】:

  • 我刚刚分解成最小的部分。 JOIN NetRate_Quote_Insur_Quote_Locat_Liabi 中的最后一个表是问题所在。不同的LocationID 有很多ClassCodeDescription。我在这里有什么选择?
  • ShooterMcGavin...基线查询给了我 15,958 条记录,第二个查询给了我 14,734 条记录
  • 听起来最后一个表需要以某种方式进行限制,然后才能将其加入主查询。我们是否知道某个 ClassCode 或 Description 来限制这些记录,或者这甚至重要吗?无论 ClassCode/Description 是什么,我们能否只获得第一个列出的记录? INNER JOIN (SELECT * FROM NetRate_Quote_Insur_Quote_Locat_Liabi nqI JOIN (SELECT LocationID, MAX(ClassCode) FROM NetRate_Quote_Insur_Quote_Locat_Liabi GROUP BY LocationID) nqA ON nqA.LocationID = nqI.LocationID) QLL ON QLL.LocationID = QL.LocationID
  • 是的,我认为这可行,但我应该把那条查询放在哪里?在我的选择语句中?不好意思,我做sql没那么久
  • 没关系。该代码应替换您在 NetRate_Quote_Insur_Quote_Locat_Liabi 上的联接查询。基本上只是用我提供的加入覆盖整个加入。请记住,我提供的连接只会从该表中为每个 LocationID 返回 MAX ClassCode。所有其他 ClassCode 将被忽略。如果这不正确,我们将需要进一步确定要求以了解我们应该使用哪个 ClassCode。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-02-26
  • 2013-08-26
  • 2020-03-13
相关资源
最近更新 更多