クエリから返されると予想されるよりも多くの行を取得しています。
私はそれが私のjoinステートメントと関係があると信じています。
異なる情報を持つ複数のテーブルがあります。 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行を取得します。コピーの3つには1つのメールがあり、3つには別のメールがあります。
「Mike Pamstein」の場合、同じメールで2つの重複した行が表示されます。
結果には、各人の一意の行を1つだけ含める必要があります。
2つ目のメールを削除します。
おそらく、個人/アドレス/メール/ウェブサイトの組み合わせごとに1つのエントリを表示したいと考えています。もしそうなら、これを試してください:
_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
_句の列の一意の組み合わせごとに1つの行のみが返されます。これにより、結果に重複行が表示されるのを防ぐことができます。
注意すべき点がいくつかあります。
FROM
句では常にスキーマ修飾子を使用してください。 _FROM Person
_は_FROM dbo.Person
_にする必要があります。これにより、将来新しいスキーマを導入する場合の混乱がなくなり、クエリオプティマイザーがユーザーのデフォルトスキーマを探す必要がなくなります。
将来の保守性のために、列がどのテーブルにあるかに関係なく、列に同じ名前を付けたいと思うでしょう。たとえば、ID
テーブルのPeople
列をID
、およびPerson
テーブルではAddress
という名前が付けられているので、bothテーブルでは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分離レベル。
サブクエリを使用して、結合で1つのレコードを返すことができますか?
...
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を使用して1人に強制していますが、他のロジックを使用して、1人あたり1レコードに減らし、重複を排除することもできます。