2013-03-14 71 views
2

我不确定我的问题甚至措辞正确,但在这里。根据T-SQL中的源表填充列数据

我有了对表地址FK引用,电子邮件,电话(这些有1对多与联系人)的表称为联系人。我需要创建一个将提取所有数据的查询,并具有一个名为Contact Method的列,该列显示该行来自哪个子表。

Contact: ID, AddressID, EmailID, PhoneID 
Address: ID, Line1, City, State 
Email : ID, EAddress 
Phone : ID, Number, Extension 

我需要的结果表看起来像这样:

ContactMethod | ID | [Value1] | [Value2] | [Value3] 

Address   2  N5980 Onalaska  WI 
Email   8  [email protected] 
Phone   5  555-5555 1234 

另外,它可以列出行中的所有组合的列,如果这是简单的,我可以用正常工作。即

ContactMethad | ID | Line1 | City | State | ID | EAddress | ID | Number | Extension 

我看着PIVOT,这是整洁,但似乎并没有通过自身来解决我的问题。我需要将它与COALESCE结合吗?

感谢您的任何帮助。


编辑

我的数据,上表联系是这样的:

ID | AddressID | PhoneID | EmailID 

1  3   null  null 
2  null   null  7 
3  null   5  null 
4  4   null  null 
5  null   6   null 

提出的解决方案,除了工作,我得到的每ID 3行。合理?

+0

让我拨打[bluefeet](http://stackoverflow.com/users/426671/bluefeet)。 – Kermit 2013-03-14 19:35:04

+0

在http://mattgemmell.com/2008/12/08/what-have-you-tried/“我有什么试过桶”:我已经尝试过使用PIVOT,CASE,COALESCE的各种版本。我可以发布他们,虽然没有工作,我担心这会让我的帖子感到困惑。 – 2013-03-14 19:40:19

回答

7

可以逆转置使用CROSS APPLYVALUES子句,以获得结果的数据:

select d.ContactMethod, d.id, d.Value1, d.Value2, d.Value3 
from contacts c 
left join address a 
    on c.addressid = a.id 
left join email e 
    on c.emailid = e.id 
left join phone p 
    on c.phoneid = p.id 
cross apply 
(
    values 
    ('Address', c.addressid, a.Line1, a.City, a.State), 
    ('Email', c.emailid, e.eAddress, '', ''), 
    ('Phone', c.phoneid, p.number, cast(p.extension as varchar(10)), '') 
) d (ContactMethod, id, Value1, Value2, Value3) 

SQL Fiddle with Demo

这给出结果:

| CONTACTMETHOD | ID | VALUE1 | VALUE2 | VALUE3 | 
----------------------------------------------------- 
|  Address | 2 | N5980 | Onalaska |  WI | 
|   Email | 8 | [email protected] |   |  | 
|   Phone | 5 | 555-5555 |  1234 |  | 

如果你想你的第二个结果,那么您可以使用多个连接来得到它:

select cm.ContactMethod, 
    a.id addressid, 
    a.line1, 
    a.city, 
    a.state, 
    e.id emailid, 
    e.eaddress, 
    p.id phoneid, 
    p.number, 
    p.extension 
from contacts c 
cross join 
(
    VALUES ('Address'),('Email'),('Phone') 
) cm (ContactMethod) 
left join address a 
    on c.addressid = a.id 
    and cm.ContactMethod = 'Address' 
left join email e 
    on c.emailid = e.id 
    and cm.ContactMethod = 'Email' 
left join phone p 
    on c.phoneid = p.id 
    and cm.ContactMethod = 'Phone'; 

SQL Fiddle with Demo。其结果是:

| CONTACTMETHOD | ADDRESSID | LINE1 |  CITY | STATE | EMAILID | EADDRESS | PHONEID | NUMBER | EXTENSION | 
---------------------------------------------------------------------------------------------------------------- 
|  Address |   2 | N5980 | Onalaska |  WI | (null) | (null) | (null) | (null) | (null) | 
|   Email | (null) | (null) | (null) | (null) |  8 | [email protected] | (null) | (null) | (null) | 
|   Phone | (null) | (null) | (null) | (null) | (null) | (null) |  5 | 555-5555 |  1234 | 

编辑#1,根据你的改变,你可以改变查询到以下。

第一个与三个value列,那么你可以只添加一个WHERE子句过滤掉任何null值:

select c.ID, ContactMethod, Value1, Value2, Value3 
from contacts c 
left join address a 
    on c.addressid = a.id 
left join email e 
    on c.emailid = e.id 
left join phone p 
    on c.phoneid = p.id 
cross apply 
(
    values 
    ('Address', c.addressid, a.Line1, a.City, a.State), 
    ('Email', c.emailid, e.eAddress, null, null), 
    ('Phone', c.phoneid, p.number, cast(p.extension as varchar(10)), null) 
) d (ContactMethod, id, Value1, Value2, Value3) 
where value1 is not null 
    or value2 is not null 
    or value3 is not null 

SQL Fiddle with Demo。其结果是:

ID | CONTACTMETHOD |   VALUE1 | VALUE2 | VALUE3 | 
--------------------------------------------------------------- 
| 1 |  Address |    N5980 | Onalaska |  WI | 
| 2 |   Email |   [email protected] | (null) | (null) | 
| 3 |   Phone |   555-5555 |  1234 | (null) | 
| 4 |  Address | 1417 Saint Andrew | La Crosse |  WI | 

如果你想在一个单列的结果,那么你将要使用的UNPIVOT功能:

select * 
from 
(
    select id, 
    case col 
     when 'addressid' then 'address' 
     when 'emailid' then 'email' 
     when 'phoneid' then 'phone' end ContactMethod, 
    contact_id 
    from contacts 
    unpivot 
    (
    contact_id 
    for col in (addressid, emailid, phoneid) 
) unpiv 
) c 
left join address a 
    on c.contact_id = a.id 
    and c.ContactMethod = 'Address' 
left join email e 
    on c.contact_id = e.id 
    and c.ContactMethod = 'Email' 
left join phone p 
    on c.contact_id = p.id 
    and c.ContactMethod = 'Phone'; 

SQL Fiddle with Demo。此查询的结果是:

| ID | CONTACTMETHOD | CONTACT_ID |    LINE1 |  CITY | STATE | EADDRESS | NUMBER | EXTENSION | 
-------------------------------------------------------------------------------------------------------------- 
| 1 |  address |   2 |    N5980 | Onalaska |  WI | (null) | (null) | (null) | 
| 2 |   email |   8 |   (null) | (null) | (null) | [email protected] | (null) | (null) | 
| 3 |   phone |   5 |   (null) | (null) | (null) | (null) | 555-5555 |  1234 | 
| 4 |  address |   3 | 1417 Saint Andrew | La Crosse |  WI | (null) | (null) | (null) | 
+0

[*** + 1 ***](http://www.google.com) – Kermit 2013-03-14 19:48:31

+0

真棒,从未使用过Cross应用过。后续问题 - >我是否必须在初始SELECT中列出所有列,或者最初的SELECT是否需要与您在Cross Apply中放置的内容匹配')d(ContactMethod,id,Value1,Value2,Value3)' – 2013-03-14 19:53:11

+0

@RefractedPaladin你不明确的列被放置在'values'子句中,你会希望'select'列表只包含最终结果。以下是所有显示的示例 - 请参阅此演示 - http://sqlfiddle.com/#!3/cbe50/14 - 但您只想显示新的未转义列。合理? :) – Taryn 2013-03-14 19:56:38

0

到达第二列布局要容易得多。对于你只需要加入:

SELECT * 
FROM dbo.Contact c 
JOIN dbo.Address a 
ON c.AddressID = a.ID 
JOIN dbo. Email e 
ON c. EmailID = e.ID 
JOIN dbo. Phone p 
ON c. PhoneID = p.ID 

我只是用SELECT *,但是你必须实际列出所有列,你不希望所有的人。如果你不一定在每个子表中有一行,你需要使用LEFT OUTER JOIN而不是仅仅是JOIN

如需详细了解JOIN的结帐这个系列:http://sqlity.net/en/1146/a-join-a-day-introduction/


如果你需要多行,你可以使用这个:

SELECT * 
FROM dbo.Contact c 
CROSS JOIN (VALUES('Address','Email','Phone'))X(ContactMethod) 
LEFT JOIN dbo.Address a 
ON c.AddressID = a.ID 
AND X.ContactMethod = 'Address' 
LEFT JOIN dbo. Email e 
ON c. EmailID = e.ID 
AND X.ContactMethod = 'Email' 
LEFT JOIN dbo. Phone p 
ON c. PhoneID = p.ID 
AND X.ContactMethod = 'Phone' 

与“摊开”版去的优点是您不必处理数据类型不兼容问题。

+0

如何获取告诉我联系方法的列(即该行来自哪个表?)?谢谢 – 2013-03-14 19:42:31

+0

这将只返回一个包含地址,电子邮件和电话的行。你需要将它们分开吗? – 2013-03-14 19:47:13

+0

后者查询缺少一个ON子句。你有没有想要** CROSS **加入VALUES的东西? – 2013-03-15 06:00:00