0

次の 3 つのテーブルから、次のことを行う必要があります。

  1. People のレコードごとに 1 行を返します。複数の連絡先が関連付けられている場合は、その人物を複製しないでください。
  2. 関連付けられた ContactValue を含めます。ここで、ContactType は HOMEPHONE であり、日付範囲の開始は現在より前であり、日付範囲の終了は現在または null より後です。個人が自宅の電話を持っていない場合でも、その個人は表示されますが、ContactValue の値として NULL が表示されます。

人々

PersonId (PK、int)
FullName (nvarchar)

人連絡先

PersonId (PK、int)
ContactId (PK、int)
StartValidDate (PK、日時)
EndValidDate (日時、null)

連絡先

ContactId (PK、int)
ContactType (nvarchar)
ContactValue (nvarchar)

Peopleテーブルには、一意の人物リストが含まれています 。PeopleContactsには、各個人、さまざまな連絡先の種類、および連絡先が適している日付範囲の複数の連絡先の関連付けが含まれる場合があります。 Contactsには、特定のタイプの連絡先値のリストが含まれています。たとえば、「WORKPHONE」の ContactType と「(555) 555 5555」の ContactValue。

要件:

  1. People のレコードごとに 1 行を返します。複数の連絡先が関連付けられている場合は、その人物を複製しないでください。
  2. 関連付けられた ContactValue を含めます。ここで、ContactType は HOMEPHONE であり、日付範囲の開始は現在より前であり、日付範囲の終了は現在または null より後です。個人が自宅の電話を持っていない場合でも、その個人は表示されますが、ContactValue の値として NULL が表示されます。

People に 3 つの行が含まれている場合、次のようになります。

1     Jones, Bob
2     Smith, Bob
3     Smith, Fred

また、PeopleContacts には次の 4 つの行が含まれていました。

1     4    01/01/2012     NULL
2     1    01/01/2012     02/01/2012
2     2    02/02/2012     NULL
3     3    01/01/2012     NULL
3     4    01/01/2012     NULL

また、Contacts には次の 4 つの行が含まれていました。

1     HOMEPHONE     (555) 555 5252
2     HOMEPHONE     (666) 666 6666
3     HOMEPHONE     (777) 777 7777
4     WORKPHONE     (555) 555 5555

2012 年 2 月 2 日以降に実行した場合、正しいクエリからの出力は次のようになります。

FullName     ContactValue
--------     ------------
Jones, Bob   NULL
Smith, Bob   (666) 666 6666
Smith, Fred  (777) 777 7777

ジョーンズ、ボブは連絡先に関連付けられていますが、それは WORKPHONE に関連付けられているため、ContactValue は NULL である必要があります。Smith、Bob には 2 つの HOMEPHONE レコードへの関連付けがありますが、1 つの (666) 666 6666 だけが有効な日付範囲を持っています。Smith、Fred は、HOMEPHONE と WORKPHONE の両方に関連付けられています。

4

4 に答える 4

1

共通テーブル式を使用してこれを解決します。これは、行ごとに評価される APPLY を使用するよりも効率的です。CTE を使用すると、単一の結果セットを取得して、それに対して左外部結合を実行できます。

RANK を使用して、連絡先が 1 つだけ返されるようにします... CTE を注文し、最初のランクで CTE に参加することで、連絡先を 1 つだけ取得します。

SQL は次のようになります。

WITH [CTE] AS (
SELECT
        pc.PersonId
    ,   pc.ContactValue
    ,   RANK() OVER (PARTITION BY PersonId ORDER BY ContactValue DESC) AS [Seed]
FROM
    PeopleContacts pc
    INNER JOIN  Contacts c ON (pc.ContactId = c.ContactId AND c.ContactType='HOME')
    WHERE pc.StartValidDate <= GETDATE()
    AND (pc.EndValidDate > GETDATE() OR pc.EndValidDate IS NULL)
)

SELECT      FullName
        ,   ISNULL(CTE.ContactValue, '') 
FROM People p
LEFT OUTER JOIN CTE ON (CTE.PersonId = p.PersonID AND CTE.Seed = 1)

(このコードはテストされていません。SQL フィドルをセットアップすると、喜んで動作します)

于 2012-07-06T21:48:13.207 に答える
0

次のクエリは正しいようです。

SELECT A.FullName, B.ContactValue
FROM People A
LEFT JOIN ( SELECT  X.PersonId,
                    Y.ContactValue,
                    ROW_NUMBER() OVER (PARTITION BY X.PersonId ORDER BY ContactId ) AS RowNumber
            FROM PeopleContacts X
            LEFT JOIN Contacts Y ON Y.ContactId = X.ContactId 
        ) B ON B.PersonId = A.PersonId AND B.RowNumber = 1
于 2012-07-07T07:38:52.433 に答える
0

次のコードは正しいようです。

declare @tPeoples table (
    id int,
    name nvarchar(50)
)

declare @tContacts table (
    id int,
    type char(10),
    value nvarchar(50)
)

declare @tPeopelContact table (
    peopleId int,
    contactId int,
    starting datetime2,
    ending datetime2
)

insert into @tPeoples (id, name) values
(1, 'Jones, Bob'),
(2, 'Smith, Bob'),
(3, 'Smith, Fred')

insert into @tContacts (id, type, value ) values
(1,     'HOMEPHONE',  '(555) 555 5252'),
(2,     'HOMEPHONE',  '(666) 666 6666'),
(3,     'HOMEPHONE',  '(777) 777 7777'),
(4,     'WORKPHONE',  '(555) 555 5555'),
(5,     'HOMEPHONE',  '(000) 123 5252')

insert into @tPeopelContact (peopleId, contactId, starting, ending) values
(1,     4,    '20120101',    NULL),
(2,     1,    '20120101',   '20120201'),
(2,     2,    '20120201',     NULL),
(3,     3,    '20120101',     NULL),
(3,     4,    '20120101',     NULL)


declare @currentdate datetime
declare @type char(10)

set @currentdate = '20120202'
set @type = 'HOMEPHONE'

select
    p.name, vc.value
from
    @tPeoples p
    left join 
        (select
            ROW_NUMBER () over (partition by peopleId order by starting) as rn, *
        from
            @tPeopelContact pc
            join @tContacts c on pc.contactId = c.id
        where 
            type = @type and
            starting < @currentdate and ( ending is null or ending >= @currentdate) 
        ) vc on rn = 1 and vc.peopleId = p.id
于 2012-07-06T21:39:24.140 に答える
0

次のクエリは必要なことを行っていると思いますが、フィードバックやこれを行うためのより良いアプローチが欲しいです:

SELECT FullName, c.ContactValue FROM People p
OUTER APPLY
    (
    SELECT TOP 1 ContactValue FROM PeopleContacts pc 
    LEFT OUTER JOIN Contacts c ON pc.ContactId = c.ContactId AND c.ContactType='HOME'
    WHERE pc.PersonId = p.PersonId
    AND pc.StartValidDate <= GETDATE()
    AND (pc.EndValidDate > GETDATE() OR pc.EndValidDate IS NULL)
    ORDER BY ContactValue DESC) c
于 2012-07-06T20:50:47.440 に答える