SQL join beween tables with if statement - sql

Say, I have the following two tables:
Table customer:
id, salutation, forename, lastname, companyID
and a table company:
Company_id, Company_name, Company_address
and I want to have an evaluation over all users and their company (if they belong to one)
salutation, forename, lastname, companyName
that would amount basically to a very easy script:
select salutation, forename, lastname, company_name
from customer, company
where companyID=Company_id;
The trouble now is just, that companyID can be null. (A customer doesn't need to be part of a company). And since there is no companyID null entry in the company table and any customer who has no company ID listed is omitted due to the joint statement.
Of couse I could divide it into two scripts one for companyid=null and one for not null and mix them with a UNION command, but is there perhaps something like an if statement?
something like:
select salutation, forename, lastname, placeholder
from customer, company
where
if companyID=null then placeholder=null
else (companyID=Company_id and placeholder=company_name);
?
I know there is a case statement, that can check on the field's value and return something else instead, but is there a way to combine that with a joint to another table?

You are looking for an outer join:
select cu.salutation, cu.forename, cu.lastname, co.company_name
from customer cu
left join company co on cu.companyID = co.Company_id;
In general you should stop using the ancient implicit join syntax in the where clause and use an explicit JOIN operator. That is also the only cross-DBMS way to actually do an outer join (all DBMS that supported some proprietary outer join syntax have deprecated that)

Try this
select salutation, forename, lastname, placeholder
from customer, company
where
(companyID=null and placeholder=null )
OR
(companyID=Company_id and placeholder=company_name);

Use a left join instead of an inner join
select a.salutation, a.forename, a.lastname, a.company_name
from customer a
left outer join company b
on a.companyID=b.companyID;

Related

how to do a left join with no duplicate columns?

I have to join 2 tables and the first table I'm joining consists of:
Physicians (ID, FirstName, LastName, PracticeID, SpecialtyID, Email)
and the second table I have is:
PhysicianSpecialties( SpecialtyID, SpecialtyName)
I wrote this query to join the tables together
Select *
from physicians
right join PhysicianSpecialities
on PhysicianSpecialities.SpecialtyID = Physicians.SpecialtyID
and when I left Join them the table is now
(ID, FirstName, LastName, PracticeID, SpecialtyID, Email, SpecialtyID, SpecialtyName)
how can I rewrite this so there is only one "SpecialtyID" Column?
You didn't specify the DBMS product you are using, but: in standard SQL you can join with the USING operator if the join columns have the same name in both tables.
In this case, the "duplicated" column will automatically be removed from the result.
Select *
from physicians
right join PhysicianSpecialities using (SpecialtyID)
Not all DBMS products support that though.
You need to specify the column names of both tables instead of (*)
Select a.*,b.SpecialtyName
from physicians a
right join PhysicianSpecialities b
on b.SpecialtyID = a.SpecialtyID
Use
SELECT
physicians.ID, physicians.FirstName, physicians.LastName,
physicians.PracticeID, physicians.SpecialtyID, physicians.Email,
PhysicianSpecialities.SpecialtyName
instead of SELECT *, hence your query goes like:
SELECT
physicians.ID, physicians.FirstName, physicians.LastName,
physicians.PracticeID, physicians.SpecialtyID, physicians.Email,
PhysicianSpecialities.SpecialtyName
FROM
physicians
LEFT JOIN
PhysicianSpecialities ON Physicians.SpecialtyID = PhysicianSpecialities.SpecialtyID;
I hope it will return the desired result.

How do I check for occurrence in two tables simultaneously

I have a SQL query (oracle) that checks for both persons and firms, the problem is that you won't find a company in the user table and the other way around.
As of now I write this in two queries, but I would like to make this into one query (for example if I can get some help creating a temporay table)
I have a info table that tells me if this is a user, a company or both
The sql looks a bit like this:
Table1:
fk_id,
info1,
info2,
info3
Info_table:
fk_id,
<info if user, company or both>
User_table:
firstname,
lastname,
adress,
fk_id
Company_table:
Companyname,
adress,
fk_id
I would like to eighter 1:
Make a temporary table that looks like this:
Temptable:
fk_id,
firstname(if user or both, else empty),
lastname(if user, else companyname),
adress
or make a query like this:
select table1.info1, table1.info2, firstname, lastname, adress
from table1,
user_table,
company_table,
info_table
where table1.fk_id = user_table.fk_id (if user or both)
or table1.fk_id = company_table.fk_id (if company)
Any tips on how to solve this would be great. What is the best solution (making a temp table or to add this into the initial query)?
Use left outer join (in this response i'll use the + operator for convenience)
select table1.info1, table1.info2,
firstname,
nvl(lastname,company_name) lastname,
nvl(user_table.adress,company_table.adress) adress
from table1,
user_table,
company_table,
info_table
where
table1.fk_id=info_table.fk_id(+)
and table1.fk_id = user_table.fk_id(+) --(if user or both)
and table1.fk_id = company_table.fk_id(+) --(if company)
You can use a union:
quick example:
select firstname
,lastname as name
,'person_table' as source_table
from person_table
union
select null
,company_name
,'company_table'
from company_table;
The result will be a list of both persons and companies.
The correct way to write this query:
select t1.info1, t1.info2, ut.firstname,
coalesce(ut.lastname, ct.company_name) as lastname,
coalesce(ut.adress, ct.adress) as address
from table1 t1 left join
info_table it
on t1.fk_id = it.fk_id left join
user_table ut
on t1.fk_id = ut.fk_id and
it.info in ('both', 'user') left join
company_table ct
on t1.fk_id = ct.fk_id and
ct.info in ('both', 'company') ;
Notes:
This uses proper, explicit, standard JOIN syntax, as recommended by Oracle itself.
This only does the joins when the type specifies that the join is appropriate.
This uses COALESCE(), a standard function, rather than the bespoke NVL().
All column names are qualified.
This uses table aliases, so the query is easier to write and to read.

SQL Query help - Joins

I have a couple of SQL tables which are:
customer(Id, Name, Address, PhoneNumber);
station (Id, City, Country, Location);
car(Id, Reg, Type, Milage);
contract(CustId, StationId, CarId);
I need to use these tables to find all customers who have rented a BMW. I have written out my query as:
SELECT *
FROM CUSTOMER, CAR, CONTRACT
WHERE CUSTOMER.ID = CONTRACT.CUSTID
AND CAR.TYPE = "BMW";
Would that be correct? My thinking was I need to join the tables as there is no way of knowing what customer has rented which car, but I feel like I might be doing something wrong? Any help would be appreciated.
No, your query is not correct -- it is incorrect logically and it is written poorly.
The better way to write the query is to use proper, explicit, standard JOIN syntax:
SELECT *
FROM CONTRACT co JOIN
CUSTOMER cu
ON co.CUSTID = cu.ID JOIN
CAR ca
ON co.CARID = ca.ID -- this is a guess
WHERE ca.TYPE = 'BMW';
Notes:
You are missing the JOIN condition between CONTRACT and CAR (presumably). With explicit JOIN syntax, this is pretty obvious.
I am guessing at the right JOIN condition for CAR.
Use single quotes for string constants. That is the SQL standard, although some databases do allow double quotes as well.
SELECT * is usually to be discouraged. It is generally better practice to list the columns, especially in this case when the same column name might appear in different tables.
SELECT co.Id as ContractId , Name, Address, PhoneNumber,
cu.Id as CustId , City, Country, Location,
ca.Id as CarId, Reg, Type, Milage,
FROM CONTRACT co JOIN
CUSTOMER cu
ON co.CUSTID = cu.ID JOIN
CAR ca
ON co.CARID = ca.ID
STATION st
ON co.StationId = st.ID
WHERE ca.TYPE = 'BMW';
You need to mention Column names explicitly because there will be name conflict for field Id which is common across many tables
PS: Just modifying query from Gordon Linoff answer on the same question
This should help: (You do not need to worry about Station as per your requirement)
SELECT distinct cus.*
FROM CONTRACT con
JOIN CUSTOMER cus ON con.CUSTID = cus.ID
JOIN CAR car ON co.CARID = car.ID
WHERE car.TYPE = 'BMW';

SQL Group By, Distinct confusion

I have a program that is linked to a sql DB, with 2 tables - Customers and SInfo.
Customers has the normal columns:
CUSTOMERID (Primary Key)
FIRSTNAME
LASTNAME
EMAIL
SInfo has details about the Customer:
SSheetID (Primary Key)
CustomerID
SerialNumber
When I use the query builder in .net, I use an inner join to combine the tables, and use a filter to search for a serial number, but I am getting an error when the primary key is shown more than once.
I tried to use distinct, but if one field was different, I would get the error, and GROUP BY is killing me.
So my question is, what would be the best practice if a Customer (CustomerID) has the same Serial Number more than once, but I just want to show that CustomerID once, but still fill out FirstName, LastName, Email?
Any help is appreciated.
Like what Turophile said i think the data in SInfo table got some problem.so what you should do is to clean the table SInfo first or you can try this:
select a.CustomerID,a.SerialNumber,b.FirstName from
(select distinct (CustomerID),SerialNumber from SInfo)a
inner join Customers b on a.CustomerID = b.CustomerID
You can use natural join for this case because when you use natural join, it will match people with the same Customer ID and then use GROUP BY so it will show the name one time.
select first_name, last_name, email
from customer natural join Sinfo
group by customerID, first_name, last_name, email
Various options...
via distinct:
select distinct c.* -- or better: more specific c. columns
from SInfo s
inner join Customers c on c.CUSTOMERID = s.CustomerID
where s.SerialNumber = #serial
via exists:
select *
from Customers c
where exists (
select 1 from SInfo s
where s.CustomerID = c.CUSTOMERID
and s.SerialNumber = #serial)
but as noted in the comments: a unique constraint over SInfo.SerialNumber, or perhaps spanning SInfo.SerialNumber and SInfo.CustomerID - probably makes sense.

How To Code a Multi-Join SQL Query And Get Query Results Even When 1 Table Lacks A Joining Row

I have the following query statement:
$query_string = '
SELECT customerID, lastName, firstName, companyName, email, citizenship, primaryLanguage
FROM customers
JOIN citizenships USING(citizenshipID)
JOIN languages USING(languageID)
JOIN paymentMethods USING(customerID)
WHERE customerID = "1"
';
Currently the customers, citizens and languages tables each contain rows and join properly. My query result returns 1 row for customer #1.
The paymentMethods table does not contain any rows at this time. When I add the join syntax for paymentMethods to the query string, my query result returns 0 rows for customer #1.
I want to join on paymentMethods and only return a row from the paymentMethods table when one exists without causing no customer rows to be returned otherwise.
How might I tweak my JOIN syntax to make that happen?
Thank you.
Replace it with LEFT JOIN:
SELECT customerID, lastName, firstName, companyName, email, citizenship, primaryLanguage
FROM customers
JOIN citizenships
USING (citizenshipID)
JOIN languages
USING (languageID)
LEFT JOIN
paymentMethods
USING (customerID)
WHERE customerID = "1"
$query_string = '
SELECT customerID, lastName, firstName, companyName, email, citizenship, primaryLanguage
FROM customers
JOIN citizenships USING(citizenshipID)
JOIN languages USING(primaryLanguageID)
LEFT JOIN paymentMethids USING(customerID)
WHERE customerID = "1"
';