Using conditions in joins - sql

I've below 3 tables from which need to fetch address for the records.
1. Address AD
---> It has all the address values(addrline1,addrline2,state,etc..) alongwith AddressID column
2. Address_Employee AE
---> It has EmpID,AddressID,AddressTypeID columns
There can be multiple instances of same EmpID with different AddressID and AddressTypeID value as either 3 or 1
3. Address_Type AT
---> There are 2 rows, with AddressTypeID and AddressType columns. AddressTypeID value with 1 will be Home and 3 will be Postal.
Need to fetch records in such a way that first need to look for Postal address, if not available then Home.
I'm using the query:
SELECT (AD.sAddressLine1+' '+AD.sAddressLine2+' '+AD.sSuburb+' '+AD.sPostCode) AS Address
from Address AD
INNER JOIN Address_Employee AE ON AD.AddressID = AE.AddressID
INNER JOIN Address_Type AT ON AE.AddressTypeID= AT.AddressTypeID
But how can I apply the condition: "first need to look for Postal address, if not available then Home."
Please advise.
Thanks, Krishna

You could create a view delivering the preferred address for every EmpID, and use this for furthor joins.
Create View V_Emp_With_Preferred_Address as
Select Distinct EmpID
,Case when Exists(Select * from Address_Employee where Address_Employee.EmpID=e.EmpID and AddressTypeID=3) then
( -- take preferred postal address if available
Select ISNULL(sAddressLine1+' ','')+ISNULL(sAddressLine2+' ','')+ISNULL(sSuburb+' ','')+ISNULL(sPostCode,'')
from Address_Employee
join Address on Address.AddressID=Address_Employee.AddressID
where Address_Employee.EmpID=e.EmpID and AddressTypeID=3
)
else
(
Select ISNULL(sAddressLine1+' ','')+ISNULL(sAddressLine2+' ','')+ISNULL(sSuburb+' ','')+ISNULL(sPostCode,'')
from Address_Employee
join Address on Address.AddressID=Address_Employee.AddressID
where Address_Employee.EmpID=e.EmpID and AddressTypeID=1
)
end as Address
from dbo.Address_Employee e

Related

how to eliminiate the duplicates from SQL table which has two type of data?

I have a table in my database called email. this will store the email address of all customers based on the type of email they provide. there is a column email type which tells the email is business or personal. when a customer provide business email address we will update it under type business and keep the personal email type as Null. when we try to join this table with my query it gives me duplicate data in email column as the email table has two columns(one as NULL, other one has email address). I cannot give a condition where emailaddress is not null because there are customer who doesn't have provided any email address so both of their emailtype will be null. so those records will be avoided from my query. please help me how to pull the correct email address without pulling the deplicate
I have tried using the condition where emailaddress is not null. but the query result is avoiding the data where both the emailtypes are null
select distinct
c.rtlrcontractidentifier as RetailerID,
CT.Fullname as Fullname,
ad.address1 as Address,
ad.City,
ad.provinceorstate as State,
ad.postalcode as Zip
, e.emailaddress
from contract c
inner join siteidentification si on si.siteoid=c.siteoid
inner join consumer cs on cs.consumeroid=c.billingconsumeroid
inner join contact ct on ct.contactoid=cs.billingcontactoid
left Join Address ad on ad.FKObjectOID = ct.contactOID
and ad.fktableobjectoid=1049
left join email e on e.contactoid=ct.contactoid
where c.rtlrcontractidentifier in('AG74113048'
)
I need to get the emailaddress which is updated but not with the duplicate(null). also should get the data where there is no emailaddress on both emailtypes.
What happened is that you have rows in email table, with contact_oid, and email_type
It is not specified, but I assume your email table:
contact_oid, email_type, email_address
For business emails, it will be email_type = 'B' and for personal emails, the email_type = NULL. To find only emails record that is available, instead of placing a WHERE on the email_type, use the contact_oid to determine if the row exists or not.
In this case, just changing the LEFT JOIN to INNER JOIN should work. If this is not the case, then provide some sample data to work on.
SELECT DISTINCT
c.rtlrcontractidentifier AS RetailerID
, ct.Fullname AS Fullname
-- , e.emailtype --> To show the email type
, e.emailaddress
FROM contracts AS c
INNER JOIN consumer AS cs ON cs.consumeroid = c.billingconsumeroid
INNER JOIN contact AS ct ON ct.contactoid = cs.billingcontactoid
--> Change from LEFT JOIN to INNER JOIN
INNER JOIN email AS e ON e.contactoid = ct.contactoid
WHERE c.rtlrcontractidentifier IN ('AG74113048');
I believe that another way to avoid duplicates is to specify two columns for business email and personal email:
SELECT DISTINCT
c.rtlrcontractidentifier as RetailerID,
.
.
.
be.emailaddress as businesss_email,
pe.emailaddress as personal_email
FROM contract c
.
.
.
LEFT JOIN email be on be.contactoid=ct.contactoid
LEFT JOIN email pe on pe.contactoid=ct.contactoid
WHERE c.rtlrcontractidentifier in('AG74113048') AND
be.email_type = 'Business' AND
pe.email_type = 'Personal'
If you don't like having the two columns, you should be able to combine them with:
SELECT DISTINCT
c.rtlrcontractidentifier as RetailerID,
.
.
.
ISNULL(be.emailaddress, pe.emailaddress) AS emailaddress
FROM contract c
.
.
.
LEFT JOIN email be on be.contactoid=ct.contactoid
LEFT JOIN email pe on pe.contactoid=ct.contactoid
WHERE c.rtlrcontractidentifier in('AG74113048') AND
be.email_type = 'Business' AND
pe.email_type = 'Personal'
In the above query, you will get the business email if it's not NULL, otherwise you will get the personal address.

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.
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 ...

How to write a SQL query for the below scenario

Sales
order id : 1(primary key)
Billing address id -250
Shipping address id -285
Address table has the below entries
id :250
Addressline1 : XXX
Addressline2 :YYY
id :285
Addressline1 : AAA
Addressline2 :BBB
How to write a query to retrieve the order id, billing address, shipping address in a single query ?
Use the following query with join. The below is a sample code.
select order.orderid,
ad1.Addressline1,
ad1.Addressline2,
ad2.Addressline1,
ad2.Addresslinne2
from order
join address ad1 on ad1.id=order.billingaddressid
join address ad2 on ad2.id=order.shippingaddressid
You can join to the address table multiple times (this uses an outer join -- depends on potential null values):
select s.id,
billing.Addressline1,
shipping.Addressline1
from sales s
left join address billing on s.billingaddressid = billing.id
left join address shipping on s.shippingaddressid = shipping.id
A Visual Explanation of SQL Joins

Find which rows have different values for a given column in Teradata SQL

I am trying to compare two addresses from the same ID to see whether they match. For example:
Id Adress Code Address
1 1 123 Main
1 2 123 Main
2 1 456 Wall
2 2 456 Wall
3 1 789 Right
3 2 100 Left
I'm just trying to figure out whether the address for each ID matches. So in this case I want to return just ID 3 as having a different address for Address Code 1 and 2.
Join the table with itself and give it two different aliases (A and B in the following example). This allows to compare different rows of the same table.
SELECT DISTINCT A.Id
FROM
Address A
INNER JOIN Address B
ON A.Id = B.Id AND A.[Adress Code] < B.[Adress Code]
WHERE
A.Address <> B.Address
The "less than" comparison < ensures that you get 2 different addresses and you don't get the same 2 address codes twice. Using "not equal" <> instead, would yield the codes as (1, 2) and (2, 1); each one of them for the A alias and the B alias in turn.
The join clause is responsible for the pairing of the rows where as the where-clause tests additional conditions.
The query above works with any address codes. If you want to compare addresses with specific address codes, you can change the query to
SELECT A.Id
FROM
Address A
INNER JOIN Address B
ON A.Id = B.Id
WHERE
A.[Adress Code] = 1 AND
B.[Adress Code] = 2 AND
A.Address <> B.Address
I imagine that this might be useful to find customers having a billing address (Adress Code = 1 as an example) differing from the delivery address (Adress Code = 2) .
This works for PL/SQL:
select count(*), id,address from table group by id,address having count(*)<2
You can do this using a group by:
select id, addressCode
from t
group by id, addressCode
having min(address) <> max(address)
Another way of writing this may seem clearer, but does not perform as well:
select id, addressCode
from t
group by id, addressCode
having count(distinct address) > 1
Personally, I would print them to a file using Perl or Python in the format
<COL_NAME>: <COL_VAL>
for each row so that the file has as many lines as there are columns. Then I'd do a diff between the two files, assuming you are on Unix or compare them using some equivalent utilty on another OS. If you have multiple recordsets (i.e. more than one row), I would prepend to each file row and then the file would have NUM_DB_ROWS * NUM_COLS lines

Left Join that always includes null records

I'm using Oracle 11gR2 and I am trying to write a query that returns address data from two tables, CUSTOMERS and LOCATIONS. A given customer may (or may not) have different locations, each with their own address.
I would like to return the address for every customer, and all their locations. For example, if the tables contained data like:
CUSTOMERS
CUSTOMER_ID ADDRESS
1 "New York"
2 "California"
LOCATIONS
CUSTOMER_ID LOCATION_ID ADDRESS
1 1 "New Jersey"
Then I want the results to look like:
CUSTOMER_ID LOCATION_ID ADDRESS
1 "New York"
1 1 "New Jersey"
2 "California"
My first thought was something like this:
SELECT
CUSTOMERS.CUSTOMER_ID,
LOCATIONS.LOCATION_ID,
NVL(LOCATIONS.ADDRESS,CUSTOMERS.ADDRESS) ADDRESS
FROM
CUSTOMERS
LEFT JOIN
LOCATIONS ON (CUSTOMERS.CUSTOMER_ID=LOCATIONS.CUSTOMER_ID)
The problem with that is that when a customer does have locations, it does not return a row with null values for location data, so I don't get a row with the address in the CUSTOMERS table. It gives me something like this:
CUSTOMER_ID LOCATION_ID ADDRESS
1 1 "New Jersey"
2 "California"
It's missing the New York address for customer 1. I tried this...
SELECT
CUSTOMERS.CUSTOMER_ID,
LOCATIONS.LOCATION_ID,
NVL(LOCATIONS.ADDRESS,CUSTOMERS.ADDRESS) ADDRESS
FROM
CUSTOMERS
LEFT JOIN
LOCATIONS ON (CUSTOMERS.CUSTOMER_ID=LOCATIONS.CUSTOMER_ID OR LOCATIONS.CUSTOMER_ID IS NULL)
But it gave me the same results as the first query. Is there a way to return a null record for the second table even when there is a match on the join condition?
You don't need a join here at all:
SELECT customer_id, NULL AS location_id, address
FROM customers
UNION ALL
SELECT customer_id, location_id, address
FROM locations
You can try a full outer join. For example:
SELECT
CUSTOMERS.CUSTOMER_ID,
LOCATIONS.LOCATION_ID,
NVL(LOCATIONS.ADDRESS,CUSTOMERS.ADDRESS) ADDRESS
FROM CUSTOMERS
FULL OUTER JOIN LOCATIONS ON (CUSTOMERS.CUSTOMER_ID=LOCATIONS.CUSTOMER_ID)
If you want to join the two tables even when there is a non match, you will need to use IS NULL on your joined columns.
For example.
Table 1:
CustomerID
CustomerName
.
Table 2:
CustomerID
CustomerEmail
.
Select,
CustomerID,
CustomerName,
ISNULL (CustomerEmail, NULL) AS CustomerEmail
FROM table1
LEFT JOIN table2
ON table1.CustomerID = table2.CustomerID
This wil bring back results with NULL