Self присоединяется вместо подзапросов - PullRequest
1 голос
/ 12 сентября 2009

Может кто-нибудь выяснить, как избавиться от операторов 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 ]

4 голосов
/ 12 сентября 2009

В SQL Server NOT IN / NOT EXISTS лучше , чем LEFT JOIN, поскольку его оптимизатор не может различить ANTI JOIN в LEFT JOIN / IS NULL. Он вернет весь набор результатов и впоследствии отфильтрует значения 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
2 голосов
/ 12 сентября 2009

Зачем вам это нужно? Правильное использование подзапросов (особенно с использованием 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
0 голосов
/ 12 сентября 2009

Вы просто должны делать соединения, где ноль.
Вот пример с использованием предоставленного вами запроса:

ВЫБРАТЬ ТОП 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],
Fm.ReversalFJNo AS [Обратный FJNo.],
CAST (ISNULL (Fm.FJAmt, 0) AS DECIMAL (9, 2)) AS Количество,
Ftc.InterfaceDescr AS [Transaction Desc],
Fm.Comments, Fm.CreatedBy AS [Автор:],
Ftm.Created, RegistrationTypeid, FJDate

ОТ FinMaster AS Fm
ВНУТРЕННЕЕ СОЕДИНЕНИЕ FinTransMaster AS Ftm ON Ftm.FjNo = Fm.FJNo
INNER JOIN dbo.Account AS Act ON Ftm.AcctID = Act.AccountId
ВНУТРЕННЕЕ СОЕДИНЕНИЕ dbo.Contact AS Cnt ON Act.PrimaryContactId = Cnt.ContactId
ВНУТРЕННЕЕ СОЕДИНЕНИЕ FinTransCode 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 <> 'PYMT') И FJDate> getdate () - 5

ЗАКАЗАТЬ по Ftm.Created DESC

0 голосов
/ 12 сентября 2009

Я думаю, что вы могли бы выполнить OUTER JOINs для таблиц FinMaster и FinTransMaster, и чтобы предложение where указывало, что идентификаторы из этих таблиц равны нулю.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...