将三行(带空值)中的数据合并为一个

时间:2015-07-28 21:25:02

标签: sql sql-server tsql

我有三张桌子:

Profile
  -ProfileID
  -FirstName
  -LastName

ProfilePhoneNumber
  -ProfileID
  -PhoneNumberID

PhoneNumber
  -PhoneNumberID
  -PhoneNumberTypeID
  -Number

ProfilePhoneNumberProfilePhoneNumber之间的简单桥牌表。

我想查询特定的电话号码类型并返回单行。我希望能够接受null值,因为并非所有人都拥有所有类型的电话号码。

这是我当前的查询:

SELECT
      p.FirstName
    , p.LastName
    , bpn.Number as BusinessPhoneNumber
    , mpn.Number as MobilePhoneNumber
FROM Profile p
LEFT JOIN ProfilePhoneNumber ppn ON p.ProfileID = ppn.ProfileID
LEFT JOIN PhoneNumber bpn ON ppn.PhoneNumberID = bpn.PhoneNumberID AND bpn.PhoneNumberTypeID = '1'
LEFT JOIN PhoneNumber mpn ON ppn.PhoneNumberID = mpn.PhoneNumberID AND mpn.PhoneNumberTypeID = '2'
WHERE p.ProfileID = '123'

这总是有效,但返回三行,因为Profile 123有三个电话号码,因此查询会为每个电话号码返回一行。

如果我在INNER JOIN上将其更改为PhoneNumber,我只能返回一行,但仅在查询的配置文件具有所有PhoneNumberTypeID类型的情况下我正在查询。

如何返回一个空容忍的行?

3 个答案:

答案 0 :(得分:2)

如果您提供一些数据样本和预期输出,我稍后会更新查询。

到目前为止,这有帮助吗?

SELECT
      p.FirstName
    , p.LastName
    , Max(bpn.Number) as BusinessPhoneNumber
    , Max(mpn.Number) as MobilePhoneNumber

FROM Profile p
    LEFT JOIN ProfilePhoneNumber ppn on p.ProfileID = ppn.ProfileID
        LEFT JOIN PhoneNumber bpn on ppn.PhoneNumberID 
         = bpn.PhoneNumberID AND bpn.PhoneNumberTypeID = '1'
        LEFT JOIN PhoneNumber mpn on ppn.PhoneNumberID 
         = mpn.PhoneNumberID AND mpn.PhoneNumberTypeID = '2'

WHERE p.ProfileID = '123'
group by p.FirstName, p.LastName;

答案 1 :(得分:2)

If each profile has one phone per type then you can:

  1. Use INNER JOIN queries to match profile with each phone type
  2. Use LEFT JOIN query to match the profiles with the above

DDL:

CREATE TABLE profile (ProfileID INT NOT NULL, FirstName VARCHAR(100), LastName VARCHAR(100), PRIMARY KEY (ProfileID));
INSERT INTO profile (ProfileID, FirstName, LastName) VALUES (1, 'User', '#1'), (2, 'User', '#2'), (3, 'User', '#3');

CREATE TABLE phonenumber (PhoneNumberID INT NOT NULL, PhoneNumberTypeID INT, Number VARCHAR(100), PRIMARY KEY (PhoneNumberID));
INSERT INTO phonenumber (PhoneNumberID, PhoneNumberTypeID, Number) VALUES (1, 1, '0800-U1BUS'), (2, 1, '0800-U2BUS'), (3, 2, '0800-U2MOB'), (4, 1, '0800-U3BUS'), (5, 2, '0800-U3MOB'), (6, 3, '0800-U3ETC');

CREATE TABLE profilephonenumber (ProfileID INT NOT NULL, PhoneNumberID INT NOT NULL, PRIMARY KEY (ProfileID,PhoneNumberID));
INSERT INTO profilephonenumber (ProfileID, PhoneNumberID) VALUES (1, 1), (2, 2), (2, 3), (3, 4), (3, 5), (3, 6);

Query:

SELECT Profile.FirstName, Profile.LastName, BusPhone.Number AS BusPhoneNumber, MobPhone.Number AS MobPhoneNumber
FROM profile
LEFT JOIN (
    SELECT ProfileID, Number
    FROM profilephonenumber
    INNER JOIN phonenumber ON profilephonenumber.PhoneNumberID = phonenumber.PhoneNumberID
    WHERE PhoneNumberTypeID = 1
) AS BusPhone ON Profile.ProfileID = BusPhone.ProfileID
LEFT JOIN (
    SELECT ProfileID, Number
    FROM profilephonenumber
    INNER JOIN phonenumber ON profilephonenumber.PhoneNumberID = phonenumber.PhoneNumberID
    WHERE PhoneNumberTypeID = 2
) AS MobPhone ON Profile.ProfileID = MobPhone.ProfileID

Output:

+-----------+----------+----------------+----------------+
| FirstName | LastName | BusPhoneNumber | MobPhoneNumber |
+-----------+----------+----------------+----------------+
| User      | #1       | 0800-U1BUS     | NULL           |
| User      | #2       | 0800-U2BUS     | 0800-U2MOB     |
| User      | #3       | 0800-U3BUS     | 0800-U3MOB     |
+-----------+----------+----------------+----------------+

SQL Fiddle

答案 2 :(得分:0)

-- Sample data.
declare @Profile as Table ( ProfileId Int Identity, FirstName VarChar(10), LastName VarChar(10) );
insert into @Profile ( FirstName, LastName ) values
  ( 'Alice', 'Aardvark' ), ( 'Bob', 'Bear' ), ( 'Cindy', 'Cat' );

declare @PhoneNumber as Table ( PhoneNumberId Int Identity, PhoneNumberTypeId Int, Number VarChar(10) );
insert into @PhoneNumber ( PhoneNumberTypeId, Number ) values
  ( 1, '1111111111' ), ( 2, '1112221111' ), ( 1, '1113331111' ), ( 2, '2222222222' );

declare @ProfilePhoneNumber as Table ( ProfileId Int, PhoneNumberId Int );
insert into @ProfilePhoneNumber ( ProfileId, PhoneNumberId ) values
  ( 1, 1 ), ( 1, 2 ),
  ( 2, 3 ),
  ( 3, 4 );

-- Dump the sample data.
select *
  from @Profile as P left outer join
    @ProfilePhoneNumber as PPN on PPN.ProfileId = P.ProfileId left outer join
    @PhoneNumber as PN on PN.PhoneNumberId = PPN.PhoneNumberId;

-- Do the deed.
with ExtendedPhoneNumbers as (
  select ProfileId, PhoneNumberTypeId, Number
    from @ProfilePhoneNumber as PPN inner join
      @PhoneNumber as PN on PN.PhoneNumberId = PPN.PhoneNumberId )
  select P.FirstName, P.LastName,
    EPNB.Number as BusinessPhoneNumber,
    EPNM.Number as MobilePhoneNumber
  from @Profile as P left outer join
    ExtendedPhoneNumbers as EPNB on P.ProfileID = EPNB.ProfileID and EPNB.PhoneNumberTypeId = 1 left outer join
    ExtendedPhoneNumbers as EPNM on P.ProfileID = EPNM.ProfileID and EPNM.PhoneNumberTypeId = 2
  where P.ProfileId = 2; -- Comment out the WHERE clause to see all profiles.