連接多個表會導致重複行
我得到的行數比我期望的查詢返回的多。
我相信這與我的加入聲明有關。
有多個表,其中包含不同的資訊。
Person
包含有關此人的主要資訊,但不包含地址、電話或電子郵件。這是因為最初的設計師希望桌子能夠容納多個電話號碼、電子郵件和地址。SELECT (person.FirstName + ' ' + person.LastName) as FullName ,ISNULL(Person.isClient, '') ,ISNULL(Person.UDF1, '') ,ISNULL(Address.City, '') ,ISNULL(Address.state, '') ,PersonAddress.Person ,PersonAddress.Address ,ISNULL(Phone.PhoneNumber, 'N/A') ,Email.Email ,Person.Website FROM Person left join PersonAddress on Person.ID = PersonAddress.Person left join Address on PersonAddress.Address = Address.ID left join PersonPhone on Person.ID = PersonPhone.Person left join Phone on PersonPhone.Person = Phone.ID left join Email with (nolock) on Person.ID = Email.Person WHERE ( isclient = 'prospect' or isclient = 'client' ) and Address is not null and name like '%Mike%' ORDER BY isClient asc;
對於此範例,我得到 6 行“Mike Worths”。其中 3 份有一封電子郵件,三份有另一封電子郵件。
對於“Mike Pamstein”,我收到兩行相同的電子郵件。
我需要結果只包含每個人的一個唯一行。
我想刪除第二封電子郵件。
大概,您希望為每個獨特的人/地址/電子郵件/網站組合看到一個條目。如果是這樣,試試這個:
SELECT (person.FirstName + ' ' + person.LastName) as FullName , ISNULL(Person.isClient, '') , ISNULL(Person.UDF1, '') , ISNULL([Address].City, '') , ISNULL([Address].[state], '') , PersonAddress.Person , PersonAddress.[Address] , ISNULL(Phone.PhoneNumber, 'N/A') , Email.Email , Person.Website FROM dbo.Person LEFT JOIN dbo.PersonAddress ON Person.ID = PersonAddress.Person LEFT JOIN dbo.[Address] ON PersonAddress.[Address] = [Address].ID LEFT JOIN dbo.PersonPhone ON Person.ID = PersonPhone.Person LEFT JOIN dbo.Phone ON PersonPhone.Person = Phone.ID LEFT JOIN dbo.Email WITH (NOLOCK) ON Person.ID = Email.Person WHERE ( isclient = 'prospect' or isclient = 'client' ) and [Address] is not null and name like '%Mike%' GROUP BY (person.FirstName + ' ' + person.LastName) , ISNULL(Person.isClient, '') , ISNULL(Person.UDF1, '') , ISNULL([Address].City, '') , ISNULL([Address].state, '') , PersonAddress.Person , PersonAddress.[Address] , ISNULL(Phone.PhoneNumber, 'N/A') , Email.Email , Person.Website ORDER BY isClient asc;
最後的
GROUP BY
子句確保子句中每個唯一的列組合只返回一行GROUP BY
。這應該可以防止結果中顯示重複的行。有幾點需要注意:
- 始終在
FROM
子句上使用模式限定符。FROM Person
應該FROM dbo.Person
-> 如果您將來引入新模式,這將消除任何混亂,並防止查詢優化器不得不為您的使用者尋找預設模式。- 為了將來的可維護性,您可能希望將列命名為相同,而不管它們在哪個表中。因此,例如,不是表中的
ID
列People
被命名ID
,而是Person
在表中被命名Address
,我將它命名PersonID
為兩張桌子。這可以防止在連接中出現混淆(讀取錯誤),例如dbo.Person LEFT JOIN dbo.Address ON Person.ID = Address.Person
.- 而不是像命名表一樣
Person
,它們應該以它們包含的項目集合命名,複數形式。所以,Person
變成People
,Address
變成Addresses
。這消除了混淆 ->Address
表實際上包含單個地址還是多個地址?WITH (NOLOCK)
除非您完全理解讀取已被其他事務修改但尚未送出的行的後果,否則應該像瘟疫一樣避免這種情況。來自 MSDN:在 READ UNCOMMITTED 級別執行的事務不會發出共享鎖,以防止其他事務修改目前事務讀取的數據。READ UNCOMMITTED 事務也不會被排他鎖阻塞,排他鎖會阻止目前事務讀取已修改但未由其他事務送出的行。設置此選項時,可以讀取未送出的修改,稱為臟讀。可以更改數據中的值,並且可以在事務結束之前在數據集中出現或消失行。此選項與在事務中的所有 SELECT 語句中的所有表上設置 NOLOCK 具有相同的效果。這是隔離級別中限制最少的。
在 SQL Server 中,您還可以最大限度地減少鎖定爭用,同時保護事務免受未送出數據修改的髒讀,使用以下任一方法:
> > READ_COMMITTED_SNAPSHOT 數據庫選項設置為 ON 的 READ COMMITTED 隔離級別。 > > > SNAPSHOT 隔離級別。 > > >
您可以像這樣使用子查詢在您的聯接中返回一條記錄嗎?
... FROM dbo.Person LEFT JOIN (SELECT MAX(AddressID) AS AddressID, Person FROM dbo.PersonAddress GROUP BY Person) PersonAddress ON Person.ID = PersonAddress.Person LEFT JOIN dbo.[Address] ON PersonAddress.[Address] = [Address].ID
在這種情況下,我只是使用 MAX 將其強制為一個人,但您可以使用其他邏輯將其降低為每人一條記錄,並以這種方式消除重複項。