swam swam - 6 months ago 27
SQL Question

PostgreSQL - Creating temporary columns instead of multiple rows

I'm working with PostgreSQL customer records.

My task is to export customer records.

I have another table aside from customers with contact information.

One contact item per line (phone, value or email, value, etc.).

When I join and relate the data, I pull multiple records per customer ID (if more than 1 comm type for each customer, example phone and email).

How could I instead of making another row for each comm type, put the info into a temporary column like a phone column, a fax column, and an email column -- then have only 1 row for each customer.

edit -- you guys are masters

Database tables w/ columns:

account {
id
accountid
title (company name?)
shiptoaddress_id (links to address table)
billtoaddress_id (links to address table)
}

address {
city
country
state
name (company name?)
street1
street2
street3
zip
id
}

comlink {
isdeleted
type [Phone,Fax,E-mail,Cell,IM,FaceBook,Twitter,LinkedIn,Web Site,Other]
value
id
party_id (links to party table)
}

party {
isdeleted [t,f]
firstname
lastname
prefix
salutation
suffix
id
address_id
jobtitle_id
}

party_comlinks {
party_id (links to party table ex: fname lname...)
comlinks_id (links to comlink table phone, email, etc 1 item per row)
}


So what I want to do is pull all customers with the following data:

customer.id, customer.accountid, customer.title, shipping.name, shipping.street1, shipping.street2, shipping.street3, shipping.city, shipping.state, shipping.zip, billing.name, billing.street1 (etc), billing.city, billing.state, billing.zip, party.contactperson (as party.firstname + party.lastname) AND have phone, email, fax

I'm not sure if this will be possible as in the system I think you can have multiple shipping info, billing info, contact info for each customer... however where each shipping info and billing info is the same, I only want one row of phone, email, fax, etc and not multiple rows for each phone, email, fax, etc.

Clear as mud, right? :-)

edit -- may have gotten it now, but would still appreciate input

SELECT account.id, account.accountid, account.status, account.title AS "customer",
party.firstname AS "firstname", party.lastname as "lastname", address.name AS "billname",
address.street1 AS "billtostreet1", address.street2 AS "billtostreet2", address.city as "billtocity",
address.state AS "billtostate", address.zip AS "billtozip", address2.name AS "shiptoname",
address2.street1 as "shiptostreet1", address2.street2 AS "shiptostreet2", address2.city AS "shiptocity",
address2.state AS "shiptostate", address2.zip AS "shiptozip",

((SELECT a.value
FROM public.comlink a, party_comlinks b
WHERE b.party_id=party.id AND b.comlinks_id=a.id AND a.type='Phone')) AS "phone",

((SELECT a.value
FROM public.comlink a, party_comlinks b
WHERE b.party_id=party.id AND b.comlinks_id=a.id AND a.type='Fax')) AS "fax",

((SELECT a.value
FROM public.comlink a, party_comlinks b
WHERE b.party_id=party.id AND b.comlinks_id=a.id AND a.type='E-Mail')) AS "email"

FROM ( public.account account
INNER JOIN public.party party ON account.contact_id = party.id )
INNER JOIN public.comlink comlink ON party.id = comlink.party_id
INNER JOIN public.address address ON account.billtoaddress_id = address.id
INNER JOIN public.contact contact ON account.contact_id = contact.id
LEFT JOIN public.contact_shiptoaddress contact_shiptoaddress ON contact.id = contact_shiptoaddress.contact_id
LEFT JOIN public.address address2 ON contact_shiptoaddress.shiptoaddress_id = address2.id



WHERE account.isdeleted = 'f'

--WHERE ((comlink.type = 'E-Mail'))
--AND ((account.walkin is null OR (NOT ( account.walkin ))))
--AND ((NOT ( (account."status" = 'CustomerStatusInactive') )))
--AND ((account."prospect" is null
--OR (NOT ( account."prospect" ))))

ORDER BY account.id ASC


Actually, the INNER JOIN's were not what I needed... I needed to do LEFT JOIN's as described below.

Answer

You'll have to do this by explicitly joining against the contact table multiple times. There is now way to have a "dynamic" set of output columns depending on the data.

Example:

SELECT customers.name, phone_contacts.value AS phone, fax_contacts.value AS fax, ...
FROM customers
  LEFT JOIN (SELECT * FROM contacts WHERE contact_type = 'phone') AS phone_contacts ON ...
  LEFT JOIN (SELECT * FROM contacts WHERE contact_type = 'fax') AS fax_contacts ON ...