Join tables that are not directly connected to each other - eclipselink

I have three entities:
Customer
id pk
Address
id pk
customerid
Phone
id pk
custoemrid
How would I join in JPQL the Address with Phone Entity via customerid without using Customer Entity.
Is it possible at all?
In normal Transact-SQL i would write:
select p.*
from Address a, Phone p
where a.customer = p.customerid
and a.id = 345345
Thanks.

Yes, it's possible:
select p from Phone p, Address a
where a.customer = p.customer
and a.id = 345345

Related

How to work in case in join condition

How to find city when ContactID is provided and condition is if ContactID is coming as 123 then it will look whether it is P or C, If P then it will go to Person table and returns City(USA) as output and If C then it will go to Company table and gives City(AUS) as output.
NB: all tables contain thousands of record and City value comes from run time.
Unless you're dynamically generating the query (i.e. using some language other than SQL to execute it) then you need to join on both tables anyway. If you're joining on both tables then there's no need for a CASE statement:
select *
from contacts co
left outer join person p
on co.contactid = p.contactid
and co.person_company = 'P'
left outer join company c
on co.contactid = c.contactid
and co.person_company = 'C'
You'll start noting an issue here, for every column from PERSON and COMPANY you're going to have to add some business logic to work out which table you want the information from. This can get very tiresome
select co.contactid
, case when p.id is not null then p.name else c.name end as name
from contacts co
left outer join person p
on co.contactid = p.contactid
and co.person_company = 'P'
left outer join company c
on co.contactid = c.contactid
and co.person_company = 'C'
Your PERSON and COMPANY tables seem to have exactly the same information in them. If this is true in your actual data model then there's no need to split them up. You make the determination as to whether each entity is a person or a company in your CONTACTS table.
Creating additional tables to store data in this manner is only really helpful if you need to store additional data. Even then, I'd still put the data that means the same thing for a person or a companny (i.e. name or address) in a single table.
If there's a 1-2-1 relationship between CONTACTID and PID and CONTACTID and CID, which is what your sample data implies, then you have a number of additional IDs, which have no value.
Lastly, if you're not restricting that only companies can go in the COMPANY table and individuals in the PERSON table. You need the PERSON_COMPANY column to exist in both PERSON and COMPANY, though as a fixed string. It would be more normal to set up this data model as something like the following:
create table contacts (
id integer not null
, contact_type char(1) not null
, name varchar2(4000) not null
, city varchar2(3)
, constraint pk_contacts primary key (id)
, constraints uk_contacts unique (id, contact_type)
);
create table people (
id integer not null
, contact_type char(1) not null
, some_extra_info varchar2(4000)
, constraint pk_people primary key (id)
, constraint fk_people_contacts
foreign key (id, contact_type)
references contacts (id, contact_type)
, constraint chk_people_type check (contact_type = 'P')
);
etc.
you can LEFT JOIN all 3 tables and the using a CASE statement select the one that you need based on the P or C value
SELECT
CASE c.[Person/Company]
WHEN 'P' THEN p.NAME
WHEN 'C' THEN a.Name
END AS Name
FROM Contact c
LEFT JOIN Person p on p.ContactId = c.ContactId
LEFT JOIN Company a on a.ContachId = c.ContactId
Ben's answer is almost right. You might want to check that the first join has no match before doing the second one:
select c.*, coalesce(p.name, c.name) as p.name
from contacts c left outer join
person p
on c.contactid = p.contactid and
c.person_company = 'P' left join
company co
on c.contactid = co.contactid and
c.person_company = 'C' and
p.contactid is null;
This may not be important in your case. But in the event that the second join matches multiple rows and the first matches a single row, you might not want the additional rows in the output.

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

Select rows with same other ID in join table

I'm struggling with writing this basic SQL query.
I have two tables. person and address_join.
create table person (id bigint);
create table person_address (person_id bigint, address_id bigint);
Given one person's ID I want to find other people they share an address with. It's also worth noting that a person can have more than one address.
How can I make this query return other person records that share the same address_id?
select * from person
join person_address on person_address.person_id = person.id
where person.id = ?;
You can answer this with a self join on person_address:
select pa2.*
from person_address pa1 join
person_address pa2
on pa1.address_id = pa2.address_id and
pa1.person_id <> pas2.person_id
where pa1.person_id = ?
select * from person p
join person_address a on a.person_id = p.id
WHERE EXISTS (
SELECT * FROM person_address x
WHERE x.person_id = ?
AND x.address_id = a.address_id
AND x.person_id <> p.person_id
);

How to perform join operation when three tables are linked?

I have three tables in database tbProduct, tbCompany, tbCompanyProduct
tbProduct
Product (id feild)
ProductX (product name)
tbCompany
CompanyId
CompanyName
tbCompanyProduct
Company (F.K for Company Id)
Product (F.K for Product Id)
Now I have to perform join operation for fetching all the products assigned to a company i.e on the basis of #companyid parameter...
Please help me !!!
Your query will look like this.....It is simple join between three tables...
SELECT comp.CompanyName, prod.ProductX
FROM tbCompanyProduct compPro
INNER JOIN tbCompany comp ON compPro.Company = comp.CompanyId
INNER JOIN tbProduct prod ON prod.Product = compPro.Product
WHERE comp.CompanyId = yourCompanyId

SQL Query Count - Join two tables and get a count even if it is 0

Ok, working on a query in SQL 2012 right now to join two tables and get a count. The count is how many companies are associated with a primary company. This lists exists in the same table, Contact, and they are all connected as ID of the primary company is listed in the secondary company as CompanyID. I can get a count if the primary has at least 1 secondary but I can't seem to get a count if the primary has no secondary and I need to show that 0 value. Here is my SQL query:
SELECT c.ID, c.Company, c.Category, COUNT(c1.ID) AS Secondaries
FROM Contact AS c INNER JOIN Contact AS c1 ON c.ID = c1.CompanyId
WHERE (c.MemberType = 'ORG_M') AND (c1.MemberType = 'ORG_M')
GROUP BY c.ID, c.Company, c.Category
When I do this, I get this information back:
ID Company Category Count
1 Company 1 RS_1 1
2 Company 2 RS_1 1
3 Company 3 RS_1 1
4 Company 4 RS_1 1
What I am missing is the 0 value for if a company exists in the company table but has no secondary company tied to them. How do I get that?
Use an outer join instead and move the where criteria to the join:
SELECT c.ID, c.Company, c.Category, COUNT(c1.ID) AS Secondaries
FROM Contact AS c
LEFT JOIN Contact AS c1 ON c.ID = c1.CompanyId AND c1.MemberType = 'ORG_M'
WHERE c.MemberType = 'ORG_M'
GROUP BY c.ID, c.Company, c.Category