Oracle: What is the best way to use two tables in a mutually exclusive way? - sql

I have the following sample query
select a.name,c.company
from employee a, company c
where a.comp_id = c.comp_id
and a.active='Y'
Now I have two new tables
company_profile, (Profile values for each company. Each company may or may not have data in this table)
profile_defaults (contains default profile values for each profile item independent of company)
Now I need to refer to column "show_data" in company_profile for a specific company. If there is no row for that company then i need to take the value from the profile_defaults table. How do I integrate this logic in the first query which I mentioned above in the best possible way.
Table
Employee
|Name|Comp_id|active|
Company
|Comp_id|Name|
Company_Profile
|comp_profile_id|profile_id|comp_id|profile_name|profile_value|
Profile_Defaults
|profile_id|profile_name|profile_value|
There are many other tables used. But I shortened it for four tables alone for this case now.

Try using this query:
SELECT a.name, c.company, NVL(cp.profile_value, pd.profile_value)
FROM employee a INNER JOIN company c
ON a.comp_id = c.comp_id
LEFT JOIN company_profile cp
ON c.comp_id = cp.comp_id
LEFT JOIN profile_defaults pd
ON cp.profile_id = pd.profile_id
This solution assumes that you have columns comp_id in both the company_profile and default profile_defaults tables to which you can join a record for a given company. As #PM77-1 mentioned, I use NVL() to first check the company_profile table, and default to profile_defaults if nothing is found in the former.

Related

SQL query wrong index when where on join

I have a query with joins that is not using the index that would be the best match and I am looking for help to correct this.
I have the following query:
select
equipment.name,purchaselines.description,contacts.name,vendors.accountNumber
from purchaselines
left join vendors on vendors.id = purchaselines.vendorId
left join contacts on contacts.id = vendors.contactId
left join equipment on equipment.id = purchaselines.equipmentId
where contacts.id = 12345
The table purchaselines has an index on the column vendorId, which is the proper index to use. When the query is run, I know the value of contacts.id which is joined to vendors.contactId which is joined to purchaselines.vendorId.
What is the proper way to run this query? Currently, no index is used on the table purchaselines.
If you are intending to query a specific contact, I would put THAT first since that is the primary basis. Additionally, you had left-joins to the other tables (vendors, contacts, equipment). So by having a WHERE clause to the CONTACTS table forces the equation to become an INNER JOIN, thus REQUIRING.
That said, I would try to rewrite the query as (also using aliases for simplified readability of longer table names)
select
equipment.name,
purchaselines.description,
contacts.name,
vendors.accountNumber
from
contacts c
join vendors v
on c.id = v.contactid
join purchaselines pl
on v.id = pl.vendorid
join equipment e
on pl.equipmentid = e.id
where
c.id = 12345
Also notice the indentation of the JOINs helps readability (IMO) to see how/where each table gets to the next in a more hierarchical manner. They are all regular inner JOIN context.
So, the customer ID will be the first / fastest, then to vendors by that contact ID which should optimize the join to that. Then, I would expect the purchase lines to have an index on vendorid optimizing that. And finally, the equipment table on ITs PK.
FEEDBACK Basic JOIN clarification.
JOIN is just the explicit statement of how two tables are related. By listing them left-side and right-side and the join condition showing on what relationship is between them is all.
Now, in your data example, each table is subsequently nested under the one prior. It is quite common though that one table may link to multiple other tables. For example an employee. A customer could have an ethnicity ID linking to an ethnicity lookup table, but also, a job position id also linking to a job position lookup table. That might look something like
select
e.name,
eth.ethnicity,
jp.jobPosition
from
employee e
join ethnicitiy eth
on e.ethnicityid = eth.id
join jobPosition jp
on e.jobPositionID = jp.id
Notice here that both ethnicity and jobPosition are at the same hierarchical level to the employee table scenario. If, for example, you wanted to further apply conditions that you only wanted certain types of employees, you can just add your logical additional conditions directly at the location of the join such as
join jobPosition jp
on e.jobPositionID = jp.id
AND jp.jobPosition = 'Manager'
This would get you a list of only those employees who are managers. You do not need to explictily add a WHERE condition if you already include it directly at the JOIN/ON criteria. This helps keeping the table-specific criteria at the join if you ever find yourself needing LEFT JOINs.

SQL INNER JOIN without linked column

I have an UltraGrid displaying customer information in it. The way the database is set up, there are 2 tables. Customers and Customer_Addresses. I need to be able to display all of the columns from Customers as well as Town and Region from Customer_Addresses, but I'm under the impression that I'd need Town and Region columns in the Customer table to be able to do this? I've never used an INNER JOIN before so I'm not sure if this is true or not, so can anybody give me pointers on how to do this, or if I need the matching columns or not?
Does it even require an INNER JOIN, or is there an alternative way to do this?
Below are the design views of both of the tables - Is it possible to display Add4 and Add5 from Customer_Addresses with all of Customers?
As long as you have another key column you can use to link the tables (ex. ID_Column), it is better that you use LEFT JOIN.
Example:
SELECT c.col1, ... , c.colN, a.town, a.region FROM Customers c
LEFT JOIN Customer_Addresses a ON a.ID_Column = c.ID_Column
In order to clarify how JOIN types work, look at this picture:
In our case, using a LEFT JOIN will take all information from the Customers table, along with any found matching (on ID) information from Customer_Addresses table.
First of all you need some column in common in two tables, all what you have to do is:
CREATE TABLE all_things
AS
SELECT * (or columns that you want to have in the new table)
FROM Costumers AS a1
INNER JOIN Customer_Addresses AS a2 ON a1.column_in_common = a2.column_in_common
The point is what kind of join do you want.
If you can continue the process without having information in table Costumers or in table Customer_Addresses maybe you need OUTER JOIN or other kind of JOIN.

SQL for many to one to many table

I have three tables in an Access database that I am using in java via ucanaccess.
Patients (PK Pt_ID)
Endoscopy (PK Endo_ID, FK Pt_ID)
Histology (PK Histol_ID, FK Pt_ID)
1 patient can have many endoscopies
1 patient can have many histologies
Endoscopy and histology are not related
I want to retrieve all the Endoscopies and histologies for a single patients in a single SQL query. Although I can write select statements for two tables I don't know how to do this across the three tables. Is it something like this
Select *.Endoscopy,*.Histology from Patients INNER JOIN Endoscopy, Histology ON Patient.Pt_Id=Endoscopy.Pt_ID, Patient.Pt_Id=Histology.Pt_ID
I'm sure that's a mess though...
What kind of SQL DB are you using?
I believe this works on most.
SELECT * FROM Patients, Endoscopy, Histology
WHERE Patient.Pt_Id=Endoscopy.Pt_ID
AND Patient.Pt_Id=Histology.Pt_ID
Also, I belive you have these switched around *.Endoscopy,*.Histology If you need to use that it should be Endoscopy.*, Histology.*
You can use the following query to select both endoscopies and histologies :
SELECT p.Pt_ID
, e.Endo_ID
, h.Histol_ID
FROM Patients p
INNER JOIN Endoscopy e ON p.Pt_Id = e.Pt_ID
INNER JOIN Histology h ON p.Pt_Id = h.Pt_ID
But I'm not sure this is really what you want. You might need to map the tables Patients, Endoscopy and Histology into Java classes ? In this case, you can consider the Java Persistence API (JPA). It helps you to handle these tables in your java code. Here is a JPA Quick Guide.
First idea is to use inner join (with correct syntax) but this is wrong. inner join returns patients who have both procedure. Pure left join returns additionally patients who have none. So this is the solution:
SELECT Patients.Pt_PK, Endoscopy.*, Histology.*
FROM Patients
LEFT JOIN Endoscopy ON Patients.Pt_Id = Endoscopy.Pt_ID
LEFT JOIN Histology ON Patients.Pt_Id = Histology.Pt_ID
--exclude patients who don't have any
where coalesce(Endoscopy.Endo_ID, Histology.Histol_ID) is not null
If you have multiple Endoscopy records or multiple Histology records for the same Patient then you will receive duplicate/repeated records in your SELECT. I do no think there is a way around that unless you use 2 SELECT statements instead of 1.
SELECT Endoscopy.*, Histology.*
FROM Patients
INNER JOIN Endoscopy ON Patients.Pt_Id = Endoscopy.Pt_ID
INNER JOIN Histology ON Patients.Pt_Id = Histology.Pt_ID
To select all records on a table in the select its table name/table alias .*
INNER JOIN will only select records where there is a relationship, once one of these tables does not contain a Pt_ID where it is contained in any one of the other tables then no record will be displayed with that Pt_ID
To add additional tables continue to add additional join statements
You used Patients (with S) in one location and Patient (no S) in another, make sure you use the correct naming. I am guessing its Patients but maybe its Patient.
This statement does almost the same as the above but uses LEFT JOIN syntax so that you will always get records for both tables even if one of the two tables does not have a record for a patient.
SELECT Endoscopy.*, Histology.*
FROM Patients
LEFT JOIN Endoscopy ON Patients.Pt_Id = Endoscopy.Pt_ID
LEFT JOIN Histology ON Patients.Pt_Id = Histology.Pt_ID
WHERE Histology.Histol_ID IS NOT NULL OR Endoscopy.Endo_ID IS NOT NULL
The added WHERE clause ensures that you do not get a record with all NULL values where there is a patient but no records in either of those tables.

SQL Query multiple tables same values

I'm having an issue creating a query. Here are the specifics.
There are 2 tables company_career and company_people.
People contains person information (Name, Address, etc) and Career contains historical career information (job_title, department, etc.)
People is linked to Career by job_ref_id.
Direct_Report_id lies in the career table and contains a unique id that correlates to job_ref_id.
Example: job_ref_id = '1' results in direct_report_id ='A'. I then use the value produced from direct-report_id (i.e., 'A') and query the job_ref_id = 'A' and this produces the employee name. Since it produces the employee name (which is actually the manager) I need to know how I would query this to present this as the manager name.
I think I know what you are looking for, you just need to use joins and aliases. For example:
SELECT
cp.name AS [EmployeeName],
cp.address AS [EmployeeAddress],
cc.job_title AS [EmployeeTitle],
cc.department AS [EmployeeDept],
m.name AS [ManagerName]
FROM company_people cp
LEFT JOIN company_career cc ON cc.job_ref_id = cp.job_ref_id
LEFT JOIN company_people m ON m.job_ref_id = cc.direct_report_id

Retrieve different row from same table

i hava a set of following tables
customer(cus_id,cus_name);
jointAccount(cus_id,acc_number,relationship);
account(acc_number,cus_id)
now i want to create a select statement to list all the jointAccounts,
it should included the both customer name, and relationship.
I have no idea how to retrieve both different user name, is that possible to do this?
Generally speaking, yes. I'm assuming you mean you want to get customer info for both sides of the joint account per your jointAccount table. Not sure what database you're using so this answer is assuming MySQL.
You can join on the same table twice in a single SQL query. I'm assuming you have not yet created your tables, as you have cus_id listed twice in the jointAccount table. Typically these would be something like cus_id1 and cus_id2, which I've used in my sample query below.
Example:
SELECT c1.cus_id AS cust1_id, c1.cus_name AS cust1_name
, c2.cus_id AS cust2_id, c2.cus_name AS cust2_name, j.relationship
FROM customer c1
INNER JOIN jointAccount j
ON c1.cus_id = j.cus_id1
, customer c2
INNER JOIN jointAccount j
ON c2.cus_id = j.cus_id2
I haven't tested this but that's the general idea.
try this query:
SELECT * FROM jointAccount a LEFT JOIN customer c ON a.cus_id = c.cus_id;
just replace the * with the name of the columns you need.