How would be the right way to use EXISTS clause

2019-07-13 03:14发布

问题:

In my SP I am creating a temp table #PolicyNumbers and populating it with Policy Numbers based on the parameters that will be supplied to the SP.

CREATE TABLE #PolicyNumbers  (PolicyNumber varchar(50))
INSERT INTO #PolicyNumbers SELECT   PolicyNumber
                            FROM    PlazaInsuranceWPDataSet 
                            WHERE   State IN (SELECT * FROM [dbo].[StringOfStringsToTable](@State,','))  
                            AND Coverage IN (SELECT * FROM [dbo].[StringOfStringsToTable](@Coverage,','))
                            AND SICCode IN (SELECT * FROM [dbo].[StringOfStringsToTable](@SICCode,','))

Further below in my SP I'm using EXISTS statement to filter only those PolicyNumbers that been selected based on parameters.

WHERE   EXISTS (SELECT PolicyNumber FROM #PolicyNumbers pn WHERE pn.PolicyNumber = piwp.PolicyNumber)

So the result from #PolicyNumbers DOES contain duplicates PolicyNumbers:

Then furthure in my SP I have SELECT statement and the result also contains duplicate PolicyNumbers:

SELECT 
            PolicyNumber,
            Cast(PolicyEffectiveDate AS DATE) AS PolicyEffectiveDate,
            Cast(PolicyExpirationDate AS DATE) AS PolicyExpirationDate,
            WrittenPremium
            FROM PlazaInsuranceWPDataSet

And now I am using EXIST statement:

SELECT 
        PolicyNumber,
        Cast(PolicyEffectiveDate AS DATE) AS PolicyEffectiveDate,
        Cast(PolicyExpirationDate AS DATE) AS PolicyExpirationDate,
        WrittenPremium
        FROM PlazaInsuranceWPDataSet piwp
        WHERE   EXISTS (SELECT PolicyNumber FROM #PolicyNumbers pn WHERE pn.PolicyNumber = piwp.PolicyNumber)

Is everything correct so far? If yes, then why do I have slightly different result using SELECT statement and passing same parameters in WHERE clause using IN (@MyParameter)?

SELECT 
            PolicyNumber,
            Cast(PolicyEffectiveDate AS DATE) AS PolicyEffectiveDate,
            Cast(PolicyExpirationDate AS DATE) AS PolicyExpirationDate,
            WrittenPremium
            FROM PlazaInsuranceWPDataSet piwp
            WHERE    State IN (@State) 
                    AND SICCode IN (@SICCode)
                    AND Coverage IN (@Coverage)

回答1:

The difference between your two queries, is that the first gets a list of policy numbers where at least one of the rows in the table matches on State, SICode and Coverage. Since there are multiple rows in PlazaInsuranceWPDataSet and each can have different State, SICode and Coverage (presumably), this is not the same as selecting only rows from PlazaInsuranceWPDataSet that match on those three predicates.

Here is a simplified example:

Create Table PlazaInsuranceWPDataSet  (
    PolicyNumber varchar(1),
    State varchar(3))

Insert Into PlazaInsuranceWPDataSet 
Values  ('A', 'Qld'),
        ('A', 'NSW');

Create Table #PolicyNumbers (PolicyNumber char(1));
Insert Into #PolicyNumbers
Select PolicyNumber
  From PlazaInsuranceWPDataSet 
  Where State = 'Qld';

-- Returns all policy numbers where at least one row matches the predicate.
Select *
  From PlazaInsuranceWPDataSet As piwp
  Where Exists (Select 1 From #PolicyNumbers As pn
                Where pn.PolicyNumber = piwp.PolicyNumber);

-- Returns only rows of 'A' that match the filter predicate                    
Select *
  From PlazaInsuranceWPDataSet 
  Where State = 'Qld';

One (and only one) of the rows of policy number 'A' matches the condition so when we write down that policy number in our temp table and then compare to it later we'll get all rows of 'A' back.