I'm not sure my question is even worded correctly but here goes.
I have a table called Contacts that has FK references to tables Address, Email, Phone ( these have 1 to many with Contacts ). I need to create a query that will pull all the data and has a column called Contact Method that shows which sub table that row came from.
Contact: ID, AddressID, EmailID, PhoneID
Address: ID, Line1, City, State
Email : ID, EAddress
Phone : ID, Number, Extension
I need the resulting table to look like this:
ContactMethod | ID | [Value1] | [Value2] | [Value3]
Address 2 N5980 Onalaska WI
Email 8 myEmail@
Phone 5 555-5555 1234
Alternatively it could list all the combined columns in a row if that's simpler, I can work with that as well. ie
ContactMethad | ID | Line1 | City | State | ID | EAddress | ID | Number | Extension
I looked at PIVOT , which is neat but doesn't seem to solve my problem by itself. Do I need to combine it with COALESCE ?
Thanks for any help.
EDIT
My data, on table Contact would look like this:
ID | AddressID | PhoneID | EmailID
1 3 null null
2 null null 7
3 null 5 null
4 4 null null
5 null 6 null
The proposed solution works except that I get 3 rows per ID. Make sense?
You can unpivot the data using a CROSS APPLY
and VALUES
clause to get the result:
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)
See SQL Fiddle with Demo .
This gives the result:
| CONTACTMETHOD | ID | VALUE1 | VALUE2 | VALUE3 |
-----------------------------------------------------
| Address | 2 | N5980 | Onalaska | WI |
| Email | 8 | myEmail@ | | |
| Phone | 5 | 555-5555 | 1234 | |
If you want your second result, then you can use multiple joins to get it:
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';
See SQL Fiddle with Demo . The result is:
| 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 | myEmail@ | (null) | (null) | (null) |
| Phone | (null) | (null) | (null) | (null) | (null) | (null) | 5 | 555-5555 | 1234 |
Edit #1, based on your changes you can alter the queries to the the following.
The first one with the three value
columns, then you can just add a WHERE
clause to filter out any null
values:
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
See SQL Fiddle with Demo . The result is:
ID | CONTACTMETHOD | VALUE1 | VALUE2 | VALUE3 |
---------------------------------------------------------------
| 1 | Address | N5980 | Onalaska | WI |
| 2 | Email | myEmail@ | (null) | (null) |
| 3 | Phone | 555-5555 | 1234 | (null) |
| 4 | Address | 1417 Saint Andrew | La Crosse | WI |
If you want the results in a single row, then you will want to use the UNPIVOT
function:
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';
See SQL Fiddle with Demo . The result of this query is:
| 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) | myEmail@ | (null) | (null) |
| 3 | phone | 5 | (null) | (null) | (null) | (null) | 555-5555 | 1234 |
| 4 | address | 3 | 1417 Saint Andrew | La Crosse | WI | (null) | (null) | (null) |
It is a lot easier to get to the second column layout. For that you just need to join:
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
I just used SELECT *
, but you will have to actually list all the columns as you do not want all of them. If you do not necessarily have a row in each child table you need to use LEFT OUTER JOIN
instead of just JOIN
.
For more details about JOINs checkout this series: http://sqlity.net/en/1146/a-join-a-day-introduction/
If you need multiple rows you can use this:
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'
The advantage of going with the "spread out" version is that you do not have to deal with data type incompatibilities.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.