自联接而不是子查询

时间:2009-09-12 00:03:21

标签: sql sql-server tsql sql-server-2008

有人能弄明白如何摆脱NOT EXISTS条款中的WHERE陈述吗?

SELECT TOP 100 PERCENT 
    Ftm.AcctID AS [Acct Id], 
    Act.AccountNumber AS [Account No.], 
    Act.AccountTypeId, 
    ISNULL(Cnt.FirstName, '')+ ' ' + ISNULL(Cnt.LastName, '') AS [Full Name], 
    Ftm.FinTransTypeCode AS [Trans Type], 
    Ftm.FinTransCode AS [Trans Code], 
    Fm.FJNo AS [FJ No.],   
    Fm.ReversalFJNo  AS [Reversal FJNo.],  
    CAST(ISNULL(Fm.FJAmt,0) AS DECIMAL(9, 2))  AS Amount, 
    Ftc.InterfaceDescr AS [Transaction Desc], 
    Fm.Comments, Fm.CreatedBy AS [Posted By],   
    Ftm.Created,RegistrationTypeid, FJDate  
FROM
    FinMaster AS Fm 
    INNER JOIN FinTransMaster AS Ftm ON Ftm.FjNo = Fm.FJNo 
    INNER JOIN dbo.Account AS Act ON Ftm.AcctID = Act.AccountId
    INNER JOIN dbo.Contact AS Cnt ON Act.PrimaryContactId = Cnt.ContactId
    INNER JOIN FinTransCodes AS Ftc ON Ftc.FinTransCode = Ftm.FinTransCode
WHERE     
    (Ftm.FinTransTypeCode <> 'PYMT') AND FJDate > getdate()-5  
    AND (NOT EXISTS (SELECT '' AS Expr1  
                     FROM FinMaster  
                     WHERE (ReversalFjNo = Fm.FJNo))) 
    AND (NOT EXISTS (SELECT '' AS Expr1  
                     FROM FinTransMaster AS Ftm2  
                     WHERE (FjNo = Ftm.FjNo) AND (FjTransSeqNo < Ftm.FjTransSeqNo)))  
ORDER BY Ftm.Created DESC 

4 个答案:

答案 0 :(得分:4)

在SQL Server中,NOT IN / NOT EXISTS 比LEFT JOIN更好 ,因为它的优化器无法在LEFT JOIN / IS NULL中识别ANTI JOIN。它将返回整个结果集,然后过滤掉NULL。

WITH contacts AS (
     SELECT t.contactid,
            CASE
              WHEN t.firstname IS NULL AND t.lastname IS NULL THEN
                ''
              WHEN t.firstname IS NULL THEN
                t.lastname
              WHEN t.lastname IS NULL THEN
                t.firstname
              ELSE
                t.FirstName + ' ' t.LastName
           END AS [fullname]
      FROM dbo.CONTACT t)
SELECT TOP 100 PERCENT 
       ftm.AcctID AS [Acct Id], 
       a.AccountNumber AS [Account No.], 
       a.AccountTypeId, 
       c.fullname AS [Full Name], 
       ftm.FinTransTypeCode AS [Trans Type], 
       ftm.FinTransCode AS [Trans Code], 
       t.FJNo AS [FJ No.],   
       t.ReversalFJNo  AS [Reversal FJNo.],  
       CAST(ISNULL(t.FJAmt, 0) AS DECIMAL(9, 2)) AS Amount, 
       ftc.InterfaceDescr AS [Transaction Desc], 
       t.Comments,
       t.CreatedBy AS [Posted By],   
       ftm.Created,
       RegistrationTypeid,
       FJDate  
 FROM FINMASTER t
 JOIN FINTRANSMASTER ftm ON ftm.FjNo = t.FJNo 
                        AND ftm.FinTransTypeCode <> 'PYMT'
 JOIN dbo.ACCOUNT a ON a.accountid = ftm.AcctID 
 JOIN contacts c ON c.contactid = a.PrimaryContactId
 JOIN FINTRANSCODES ftc ON ftc.FinTransCode = ftm.FinTransCode
WHERE FJDate > getdate()-5  
  AND NOT EXISTS (SELECT NULL  
                    FROM FinMaster fm  
                   WHERE fm.ReversalFjNo = t.FJNo)
  AND NOT EXISTS (SELECT NULL
                    FROM FinTransMaster AS ftm2
                   WHERE ftm2.FjNo = ftm.FjNo 
                     AND ftm2.FjTransSeqNo < ftm.FjTransSeqNo)  
ORDER BY ftm.Created DESC

答案 1 :(得分:2)

为什么要让自己接受这个?良好地使用子查询(特别是使用IN和NOT IN)使查询更具可读性,并且它们在大多数数据库引擎上都同样快。

通常,在要选择的表上使用JOIN,为其他所有内容使用子查询会导致最清晰的查询。这就是我的建议。

SELECT TOP 100 PERCENT 
    Ftm.AcctID AS [Acct Id], 
    Act.AccountNumber AS [Account No.], 
    Act.AccountTypeId, 
    ISNULL(Cnt.FirstName, '')+ ' ' + ISNULL(Cnt.LastName, '') AS [Full Name], 
    Ftm.FinTransTypeCode AS [Trans Type], 
    Ftm.FinTransCode AS [Trans Code], 
    Fm.FJNo AS [FJ No.],   
    Fm.ReversalFJNo  AS [Reversal FJNo.],  
    CAST(ISNULL(Fm.FJAmt,0) AS DECIMAL(9, 2))  AS Amount, 
    Ftc.InterfaceDescr AS [Transaction Desc], 
    Fm.Comments, Fm.CreatedBy AS [Posted By],   
    Ftm.Created,RegistrationTypeid, FJDate  
FROM
    FinMaster AS Fm 
    INNER JOIN FinTransMaster AS Ftm ON Ftm.FjNo = Fm.FJNo 
    INNER JOIN dbo.Account AS Act ON Ftm.AcctID = Act.AccountId
    INNER JOIN dbo.Contact AS Cnt ON Act.PrimaryContactId = Cnt.ContactId
    INNER JOIN FinTransCodes AS Ftc ON Ftc.FinTransCode = Ftm.FinTransCode
WHERE     
    (Ftm.FinTransTypeCode <> 'PYMT') AND FJDate > getdate()-5  
    AND Fm.FJNo NOT IN (
                     SELECT ReversalFjNo
                     FROM FinMaster  
                     WHERE ReversalFjNo IS NOT NULL) 
    AND Ftm.FjNo NOT IN (
                     SELECT FjNo
                     FROM FinTransMaster AS Ftm2  
                     WHERE FjNo IS NOT NULL) 
    AND (FjTransSeqNo < Ftm.FjTransSeqNo)))  
ORDER BY Ftm.Created DESC

答案 2 :(得分:0)

我认为您可以在FinMaster和FinTransMaster表上执行OUTER JOIN,并使where子句指定这些表中的ID为空。

答案 3 :(得分:0)

你只需要进行连接,其中null为空 以下是使用您提供的查询的示例:

选择前100%
    Ftm.AcctID AS [Acct Id],
    Act.AccountNumber AS [账号],
    Act.AccountTypeId,
    ISNULL(Cnt.FirstName,'')+''+ ISNULL(Cnt.LastName,'')AS [全名],
    Ftm.FinTransTypeCode AS [Trans Type],
    Ftm.FinTransCode AS [Trans Code],
    Fm.FJNo AS [FJ No.],
    Fm.ReversalFJNo AS [Reversal FJNo。],
    CAST(ISNULL(Fm.FJAmt,0)AS DECIMAL(9,2))AS金额,
    Ftc.InterfaceDescr AS [交易描述],
    Fm.Comments,Fm.CreatedBy AS [发布者],
    Ftm.Created,RegistrationTypeid,FJDate

来自FinMaster AS Fm
    INNER JOIN FinTransMaster AS Ftm ON Ftm.FjNo = Fm.FJNo
    INNER JOIN dbo.Account AS Act on Ftm.AcctID = Act.AccountId
    INNER JOIN dbo.Contact AS Cnt ON Act.PrimaryContactId = Cnt.ContactId
    INNER JOIN FinTransCodes AS Ftc ON Ftc.FinTransCode = Ftm.FinTransCode

left outer join FinMaster as FM2 on FM2.ReversalFjNo = Fm.FJNo and FM2.ReversalFjNo is null
left outer join FinTransMaster AS Ftm2 on (Ftm2.FjNo = Ftm.FjNo) AND (Ftm2.FjTransSeqNo < Ftm.FjTransSeqNo)
            and Ftm2.FjNo is null

WHERE
    (Ftm.FinTransTypeCode&lt;&gt;'PYMT')和FJDate&gt; getdate() - 5

按照Ftm.Created DESC订购