如何在SQL Server 2012中分解嵌套的JOIN以便正确读取它

时间:2017-01-16 23:47:24

标签: sql-server tsql join nested

我有一个不是由我创建的存储过程。

在某些存储过程中,存在嵌套连接,我很难理解。

如何更简单地编写它以理解逻辑?还有那些被使用的原因?仅提高绩效?

SELECT *
FROM      
    dbo.tblQuotes AS tblQuotes_1 
LEFT OUTER JOIN
    dbo.lstLines ON tblQuotes_1.LineGUID = dbo.lstLines.LineGUID 
RIGHT OUTER JOIN
    dbo.tblUsers 
RIGHT OUTER JOIN
    dbo.tblQuotes 
RIGHT OUTER JOIN
    dbo.tblClaims_Claim ON dbo.tblQuotes.ControlNo = dbo.tblClaims_Claim.ControlNo 
RIGHT OUTER JOIN
    dbo.tblNoteEntries 
LEFT OUTER JOIN
    dbo.tblNoteRecipients ON dbo.tblNoteEntries.ID = dbo.tblNoteRecipients.EntryGUID 
INNER JOIN
    dbo.tblNoteDiaries ON dbo.tblNoteEntries.ID = dbo.tblNoteDiaries.EntryGUID 
INNER JOIN
    dbo.tblNoteEntities ON dbo.tblNoteEntries.NoteGUID = dbo.tblNoteEntities.NoteGUID 
INNER JOIN
    dbo.tblNoteStore ON dbo.tblNoteEntries.NoteGUID = dbo.tblNoteStore.ID 
                     AND dbo.tblNoteDiaries.NoteGUID = dbo.tblNoteStore.ID 
                     AND dbo.tblNoteEntities.NoteGUID = dbo.tblNoteStore.ID 
INNER JOIN
    dbo.lstNoteTypes ON dbo.tblNoteStore.Type = dbo.lstNoteTypes.NoteTypeID 
       ON dbo.tblClaims_Claim.ClaimGuid = dbo.tblNoteEntities.AssociatedEntityGUID 
       ON dbo.tblUsers.UserGUID = dbo.tblNoteRecipients.UserGUID 
       ON tblQuotes_1.ControlGuid = dbo.tblNoteEntities.ControlGuid 
LEFT OUTER JOIN
    dbo.tblMaxQuoteIDs ON tblQuotes_1.QuoteID = dbo.tblMaxQuoteIDs.MaxQuoteID 
LEFT OUTER JOIN
    dbo.tblInsureds ON dbo.tblNoteEntities.AssociatedEntityGUID = dbo.tblInsureds.InsuredGUID   

2 个答案:

答案 0 :(得分:2)

我通常将列表转换为缩进列表,就好像各种连接是嵌套的IF语句一样。例如:

SELECT *
FROM dbo.tblQuotes AS tblQuotes_1 
LEFT OUTER JOIN dbo.lstLines 
    ON tblQuotes_1.LineGUID = dbo.lstLines.LineGUID 
RIGHT OUTER JOIN dbo.tblUsers 
    RIGHT OUTER JOIN dbo.tblQuotes 
        RIGHT OUTER JOIN dbo.tblClaims_Claim 
            ON dbo.tblQuotes.ControlNo = dbo.tblClaims_Claim.ControlNo 
        RIGHT OUTER JOIN dbo.tblNoteEntries 
            LEFT OUTER JOIN dbo.tblNoteRecipients 
                ON dbo.tblNoteEntries.ID = dbo.tblNoteRecipients.EntryGUID 
            INNER JOIN dbo.tblNoteDiaries 
                ON dbo.tblNoteEntries.ID = dbo.tblNoteDiaries.EntryGUID 
            INNER JOIN dbo.tblNoteEntities 
                ON dbo.tblNoteEntries.NoteGUID = dbo.tblNoteEntities.NoteGUID 
            INNER JOIN dbo.tblNoteStore 
                ON dbo.tblNoteEntries.NoteGUID = dbo.tblNoteStore.ID 
                AND dbo.tblNoteDiaries.NoteGUID = dbo.tblNoteStore.ID 
                AND dbo.tblNoteEntities.NoteGUID = dbo.tblNoteStore.ID 
            INNER JOIN dbo.lstNoteTypes 
                ON dbo.tblNoteStore.Type = dbo.lstNoteTypes.NoteTypeID 
            ON dbo.tblClaims_Claim.ClaimGuid = dbo.tblNoteEntities.AssociatedEntityGUID 
        ON  dbo.tblUsers.UserGUID = dbo.tblNoteRecipients.UserGUID 
    ON tblQuotes_1.ControlGuid = dbo.tblNoteEntities.ControlGuid 
LEFT OUTER JOIN dbo.tblMaxQuoteIDs 
    ON tblQuotes_1.QuoteID = dbo.tblMaxQuoteIDs.MaxQuoteID 
LEFT OUTER JOIN dbo.tblInsureds 
    ON dbo.tblNoteEntities.AssociatedEntityGUID = dbo.tblInsureds.InsuredGUID

然后我将任何不合适的ON条件移动到正确的位置,如果我可以在不破坏查询逻辑的情况下执行它。在这种情况下,如果没有一些重要的分析,我就无法做到。

注意:老实说,我讨厌这种类型的连接序列,如果你知道表和关系,你可以将它重新组织成一个简单的连接列表,而不是奇怪的嵌套连接结构。但这取决于两件重要的事情:

  1. 这样做是为了优化查询的性能吗?
  2. 即使是现在,在我使用的最新版本的SQL Server(2014)中,也有一些查询可以通过在JOIN列表中移动表引用来优化。如果这就是将列表重组为此嵌套结构的原因,则可能会通过撤消特殊组织严重损害性能。当然,如果这是在最初的SQL Server版本中编写的,您可能需要解开这些联接,以查看查询优化器现在是否能很好地处理此结构。

    1. 这样做是因为数据规范化存在一些缺陷,实际上需要嵌套的JOIN列表才能工作吗?
    2. 永远不要低估前任的愚蠢(例如,访问The Daily WTF并浏览几分钟。)如果数据结构可以以需要笨拙和非规范化JOIN的方式相关联,将以这种方式相关。我还没有真正看到这个原因得到验证,但我知道在某些地方有一些数据结构需要这个。

答案 1 :(得分:1)

如果可读性是您的目标,那么值得注意的是您根本不需要嵌套或RIGHT JOIN。以下

  • 在数学上等效
  • 从左到右一直读取(假设您喜欢这种方式)
  • 没有嵌套
  • 没有合适的人选
  • 少了不必要的字符和行

    SELECT *
      FROM dbo.tblNoteStore              nt_str
               JOIN dbo.lstNoteTypes     nt_typ ON nt_str.[Type] = nt_typ.NoteTypeID
               JOIN dbo.tblNoteDiaries   nt_dia ON nt_str.ID = nt_dia.NoteGUID
               JOIN dbo.tblNoteEntities   entit ON nt_str.ID = entit.NoteGUID
               JOIN dbo.tblNoteEntries    entri ON nt_str.ID = entri.NoteGUID
                                                   and nt_dia.EntryGUID = entri.ID 
                                                   and entit.NoteGUID = entri.NoteGUID
          LEFT JOIN dbo.tblNoteRecipients recip ON entri.ID = recip.EntryGUID
          LEFT JOIN dbo.tblUsers            usr ON recip.UserGUID = usr.UserGUID
          LEFT JOIN dbo.tblInsureds       insur ON entit.AssociatedEntityGUID = insur.InsuredGUID
          LEFT JOIN dbo.tblClaims_Claim   claim ON entit.AssociatedEntityGUID = claim.ClaimGUID
          LEFT JOIN dbo.tblQuotes         qts_1 ON entit.ControlGUID = qts_1.ControlGUID
          LEFT JOIN dbo.lstLines          lines ON qts_1.LineGUID = lines.LineGUID
          LEFT JOIN dbo.tblMaxQuoteIDs   max_qt ON qts_1.QuoteID = max_qt.MaxQuoteId
          LEFT JOIN dbo.tblQuotes         qts_2 ON claim.ControlNo = qts_2.ControlNo 
          ;