Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 将三行(带空)中的数据合并为一行_Sql_Sql Server_Tsql - Fatal编程技术网

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

Sql 将三行(带空)中的数据合并为一行,sql,sql-server,tsql,Sql,Sql Server,Tsql,我有三张桌子: Profile -ProfileID -FirstName -LastName ProfilePhoneNumber -ProfileID -PhoneNumberID PhoneNumber -PhoneNumberID -PhoneNumberTypeID -Number ProfilePhoneNumber是Profile和PhoneNumber之间的一个简单桥接表 我想查询特定的电话号码类型并返回一行。我希望能够接受空值,因为不是所有

我有三张桌子:

Profile
  -ProfileID
  -FirstName
  -LastName

ProfilePhoneNumber
  -ProfileID
  -PhoneNumberID

PhoneNumber
  -PhoneNumberID
  -PhoneNumberTypeID
  -Number
ProfilePhoneNumber是Profile和PhoneNumber之间的一个简单桥接表

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

以下是我当前的查询:

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有三个电话号码,因此查询会为每个电话号码返回一行

如果我将其更改为PhoneNumber上的内部联接,我只能返回一行,但只有在被查询的配置文件具有我要查询的所有PhoneNumberTypeID类型的情况下

如何返回一个允许空的行?

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

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

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;

如果每个配置文件每种类型有一部手机,则您可以:

使用内部连接查询将配置文件与每个电话类型匹配 使用LEFT JOIN query将配置文件与上述配置文件匹配 DDL:

查询:

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
输出:

+------+-----+--------+--------+ |FirstName | LastName |总线电话号码|移动电话号码| +------+-----+--------+--------+ |用户| 1 | 0800-U1BUS |空| |用户| 2 | 0800-U2BUS | 0800-U2MOB| |用户| 3 | 0800-U3BUS | 0800-U3MOB| +------+-----+--------+--------+
将其更改为“选择不同”是否可以解决您的问题?如果没有,当有人有多个电话号码时,你想如何选择显示哪一个商业或移动电话号码?@APH问得好。我不确定Select distinct是否能在这里工作,或者我是否需要作弊并做TOP 1。我相信我可以添加更多的条件来提高选择性,但现在我的重点是返回一个允许空的行。示例数据、SQLFIDLE、预期输出将很有帮助……谢谢@MrSimpleMind。我将对此进行研究。我建议所有三个左连接都是相等缩进的-它们当前缩进的方式表明第二个和第三个是第一个的子查询-它们不是。在一些场景中测试这一点,但这似乎是可行的。我将这个语句包装在一个外部联接中,因为它嵌套在一个更大的查询中。
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
-- 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.