SQL How to get columns from other tables based on other columns - sql

I need to get values like
AdviserInit, AdviserSurname, MaterialName and Area using AdviserID, MaterialID and AreaCode from Chores Table as my reference.
I don't know what will be my approach in creating the query. This is what I've come up with so far:
SELECT Chores.ChoresID, Chores.ChoresDate, Materials.MaterialName,
Advisers.AdviserInit, Advisers.AdviserSurname, Area.Area,
Chores.StudentID
FROM Chores INNER JOIN Materials on Chores.MaterialID = Materials.MaterialID
INNER JOIN Advisers on Chores.AdviserID = Advisers.AdviserID
INNER JOIN Area on Chores.AreaCode = Area.AreaCode
Here's the screenshot of the relationships between the tables:

You can try this query, if you want to map all tables with main Chores Table,
SELECT Chores.ChoresID, Chores.ChoresDate, Materials.MaterialName,
Advisers.AdviserInit,Advisers.AdviserSurname, Area.Area,
Chores.StudentNo, Student.Forename
FROM (((Chores INNER JOIN Materials on Chores.MaterialID = Materials.MaterialID)
INNER JOIN Advisers on Chores.AdviserID = Advisers.AdviserID)
INNER JOIN Area on Chores.AreaCode = Area.AreaCode)
INNER JOIN Student on Student.StudentNo = Chores.StudentNo
The placement of the parentheses is important here. Basically, you need to have n - 2 left parentheses after the from clause and one right parenthesis before the start of each new join clause except for the first, where n is the number of tables being joined together.
The reason is that Access's join syntax supports joining only two tables at a time, so if you need to join more than two you need to enclose the extra ones in parentheses.

Related

What is the best way to write inner join query in SQL?

First Way:
SELECT ST.PersonID, ST.CustomerID, ST.SaleTypeID, ST.PaymentGatewayID,
ST.CustomerMembershipID, ST.CustomerPaymentGatewayID, P.Currency
FROM ServiceTransaction ST
INNER JOIN dbo.Person P ON ST.PersonID = P.PersonID;
Second Way:
SELECT ST.PersonID, ST.CustomerID, ST.SaleTypeID, ST.PaymentGatewayID,
ST.CustomerMembershipID, ST.CustomerPaymentGatewayID, P.Currency
FROM ServiceTransaction ST
INNER JOIN dbo.Person P ON P.PersonID = ST.PersonID;
I want to optimize this query in SQL. Currently I am using second way and I need expert opinion, which one is best approach.
However, any one can add some new way to optimize this query as well.
As comments suggest, they are identical in many aspects. For a personal note tho if you keep the same format it gets easier to follow so I use the following schema to keep tabs on tables where I always use lower numbered table on left side
SELECT Column_list
FROM TABLE1
INNER JOIN TABLE2
INNER JOIN TABLE3
ON Table1.ColName = Table2.ColName
ON Table1.ColName = Table3.ColName | ON Table2.ColName = Table3.ColName
This way when you are working with multiple tables and joins it is easier to follow which table is joined where and which table was mentioned first in the query.

SQL: JOIN vs LEFT OUTER JOIN?

I have multiple SQL queries that look similar where one uses JOIN and another LEFT OUTER JOIN. I played around with SQL and found that it the same results are returned. The codebase uses JOIN and LEFT OUTER JOIN interchangeably. While LEFT JOIN seems to be interchangeable with LEFT OUTER JOIN, I cannot I cannot seem to find any information about only JOIN. Is this good practice?
Ex Query1 using JOIN
SQL
SELECT
id,
name
FROM
u_users customers
JOIN
t_orders orders
ON orders.status=='PAYMENT PENDING'
Ex. Query2 using LEFT OUTER JOIN
SQL
SELECT
id,
name
FROM
u_users customers
LEFT OUTER JOIN
t_orders orders
ON orders.status=='PAYMENT PENDING'
As previously noted above:
JOIN is synonym of INNER JOIN. It's definitively different from all
types of OUTER JOIN
So the question is "When should I use an outer join?"
Here's a good article, with several great diagrams:
https://www.sqlshack.com/sql-outer-join-overview-and-examples/
The short answer your your question is:
Prefer JOIN (aka "INNER JOIN") to link two related tables. In practice, you'll use INNER JOIN most of the time.
INNER JOIN is the intersection of the two tables. It's represented by the "green" section in the middle of the Venn diagram above.
Use an "Outer Join" when you want the left, right or both outer regions.
In your example, the result set happens to be the same: the two expressions happen to be equivalent.
ALSO: be sure to familiarize yourself with "Show Plan" (or equivalent) for your RDBMS: https://www.sqlshack.com/execution-plans-in-sql-server/
'Hope that helps...
First the theory:
A join is a subset of the left join (all other things equal). Under some circumstances they are identical
The difference is that the left join will include all the tuples in the left hand side relation (even if they don't match the join predicate), while the join will only include the tuples of the left hand side that match the predicate.
For instance assume we have to relations R and S.
Say we have to do R JOIN S (and R LEFT JOIN S) on some predicate p
J = R JOIN S on (p)
Now, identify the tuples of R that are not in J.
Finally, add those tuples to J (padding any attribute in J not in R with null)
This result is the left join:
R LEFT JOIN S (p)
So when all the tuples of the left hand side of the relation are in the JOIN, this result will be identical to the Left Join.
back to you problem:
Your JOIN is very likely to include all the tuples from Users. So the query is the same if you use JOIN or LEFT JOIN.
The two are exactly equivalent, because the WHERE clause turns the LEFT JOIN into an INNER JOIN.
When filtering on all but the first table in a LEFT JOIN, the condition should usually be in the ON clause. Presumably, you also have a valid join condition, connecting the two tables:
SELEC id, name
FROM u_users u LEFT JOIN
t_orders o
ON o.user_id = u.user_id AND o.status = 'PAYMENT PENDING';
This version differs from the INNER JOIN version, because this version returns all users even those with no pending payments.
Both are the same, there is no difference here.
You need to use the ON clause when using Join. It can match any data between two tables when you don't use the ON clause.
This can cause performance issue as well as map unwanted data.
If you want to see the differences you can use "execution plans".
for example, I used the Microsoft AdventureWorks database for the example.
LEFT OUTER JOIN :
LEFT JOIN :
If you use the ON clause as you wrote, there is a possibility of looping.
Example "execution plans" is below.
You can access the correct mapping and data using the ON clause complement.
select
id,
name
from
u_users customers
left outer join
t_orders orders on customers.id = orders.userid
where orders.status=='payment pending'

SQL SELECT Statement Using Three Tables

I am trying to write a SQL Select statement to port some data from a Sybase environment to a MongoDB environment and I'm just trying to figure out the correct syntax to involve three different tables.
Basically what I need to do is do an INNER JOIN on two tables, and then do a matching check against a 3rd table. The three table names are "ar_notes", "customer_service_xref" and "service_notes_details"
This is what I tried:
SELECT * FROM ar_notes arn
LEFT JOIN customer_service_xref csx ON arn.customer_service_xref_id = csx.id_number
WHERE arn.visit_date = service_notes_details.date_of_visit
This doesn't work. I get a correlation error.
What should the syntax look like when involving three tables like this?
You said you need an INNER JOIN among three tables but your query does a LEFT JOIN between two and tries another join in the WHERE clause without refering that table in the FROM clause.
To just fix your query:
SELECT *
FROM service_notes_details snd, ar_notes arn
INNER JOIN customer_service_xref csx ON arn.customer_service_xref_id = csx.id_number
WHERE arn.visit_date = snd.date_of_visit
This is what you should use in current SQL syntax:
SELECT *
FROM ar_notes arn
INNER JOIN customer_service_xref csx ON arn.customer_service_xref_id = csx.id_number
INNER JOIN service_notes_details ON arn.visit_date = service_notes_details.date_of_visit
To be clear, this will only return lines in ar_notes that have corresponding values in customer_service_xref (joining by customer_service_xref_id) and in service_notes_details(joining by visit_date). Your original query, using LEFT JOIN would return lines from ar_notes even if there was no matching customer_service_xref_id.

Join from three tables

I have three tables in the database (with the columns I require in brackets);
Alphadata (Invoice, DateRaised, Amount, Staff)
TL Auth (Invoice)
Agents (Team Leader)
The code I'm currently trying to use to get all these columns into one query is this;
SELECT Alphadata.Invoice, Alphadata.DateRaised, Alphadata.Amount, Alphadata.Staff, Agents.TeamLeader, TlAuth.Invoice
FROM Alphadata
INNER JOIN TlAuth ON Alphadata.invoice = TlAuth.invoice
INNER JOIN Agents.Alphaname = Alphadata.Staff;
I think I've missed something. But I've got the AlphaData and TL Auth columns populating when I remove the Agents (last line) but the second I re-add that it goes awry.
You missed the name of table and ON in this line:
INNER JOIN Agents ON Agents.Alphaname = Alphadata.Staff;
SELECT Alphadata.Invoice, Alphadata.DateRaised, Alphadata.Amount, Alphadata.Staff, Agents.TeamLeader, TlAuth.Invoice
FROM (Alphadata
INNER JOIN TlAuth ON Alphadata.invoice = TlAuth.invoice)
INNER JOIN Agents ON Agents.Alphaname = Alphadata.Staff;
Try with the above. If you omit the ON clause this will result in the Cartesian Product of Agents and Alphadata. You can read more about Cartesian Product here.
EDIT 1: From your comment I guess you are using MS Access? If so I found that you need parentheses if you have more than one JOIN - see here. I've added them in the above query. Please try again.
You were missing a join condition for the second and third tables. Also, you get good mileage when writing SQL queries if you use table aliases. Note in the corrected query below that I have aliased the three tables in your query. Then, you can refer to the various columns using these alises, and the query is easier to read.
SELECT t1.Invoice,
t1.DateRaised,
t1.Amount,
t1.Staff,
t2.Invoice,
t3.TeamLeader,
FROM Alphadata t1 -- t1, t2 and t3 are aliases, or nicknames
INNER JOIN TlAuth t2 -- for the actual tables in your query
ON t1.invoice = t2.invoice
INNER JOIN Agents t3
ON t3.Alphaname = t1.Staff;

Joining Two Queries onto a Shared Table

I have been struggling with the concept of combining results of two queries together via a join on a common table and I was hoping I could gain some assistance. The following is a rough guide to the tables:
dbo.Asset (not returned in the SELECT statement, used for joins only)
- dbo.Asset.AssetID
- dbo.Asset.CatalogueID
dbo.WorkOrder
- WorkOrderID
- AssetID
- WorkOrderNumber
dbo.WorkOrderSpare
- WorkOrderID
- WorkOrderSpareID
- WorkOrderSpareDescription
- ActualQuantity
- CreatedDateTime
dbo.Catalogue
- CatalogueID (PK)
- CatalogueNumber
- CatalogueDescription
- CatalogueGroupID
dbo.CatalogueGroup
- CatalogueGroupID
- CatalogueGroupNumber
First Query:
SELECT CatalogueGroup.CatalogueGroupName,
Catalogue.CatalogueNumber,
Catalogue.CatalogueDescription,
Catalogue.CatalogueID,
Asset.IsActive
FROM CatalogueGroup
INNER JOIN Catalogue
ON CatalogueGroup.CatalogueGroupID = Catalogue.CatalogueGroupID
INNER JOIN Asset
ON Catalogue.CatalogueID = Asset.CatalogueID
Second Query:
SELECT WorkOrder.WorkOrderNumber,
WorkOrderSpare.WorkOrderSpareDescription,
WorkOrderSpare.ActualQuantity,
WorkOrderSpare.CreatedDateTime
FROM WorkOrder
INNER JOIN WorkOrderSpare
ON WorkOrder.WorkOrderID = WorkOrderSpare.WorkOrderID
Now I can do the above easily enough in Access (WYSIWYG) by joining Asset/Catalogue/CatalogueGroup together and then joining Asset.AssetID onto WorkOrder.AssetID. I can't seem to get anything similar to work via raw code, I think I have my logic correct for the joins (INNER JOIN on the results of both) but then I am new to this.
Any assistance would be greatly appreciated, any pointers on where I can read further into problems like this would be great.
EDIT: This is what I was trying to use to no avail, I should also mention I am trying to do this in ms-sql, not Access (trying to move away from drag and drop):
SELECT CatalogueGroup.CatalogueGroupName,
Catalogue.CatalogueNumber,
Catalogue.CatalogueDescription,
Catalogue.CatalogueID,
Asset.IsActive,
WorkOrderSpare.WorkOrderSpareDescription,
WorkOrderSpare.ActualQuantity,
WorkOrderSpare.CreatedDateTime,
WorkOrder.WorkOrderNumber
FROM (((CatalogueGroup
INNER JOIN Catalogue
ON CatalogueGroup.CatalogueGroupID = Catalogue.CatalogueGroupID)
INNER JOIN Asset ON Catalogue.CatalogueID = Asset.CatalogueID)
INNER JOIN WorkOrderSpare
ON WorkOrder.WorkOrderID = WorkOrderSpare.WorkOrderID)
INNER JOIN WorkOrder ON Asset.AssetID = WorkOrder.AssetID
Think I see the issue. Assuming that the joins themselves are correct (ie your columns do relate to each other), the order of your joins is a little off - when you join WorkOrder to WorkOrderSpare, neither of those two tables relate back to any table you've identified up until that point in the query. Think of it as joining two tables separately from the chain of joins you have going so far - it's almost like doing two separate join queries. If you switch the last two it should work, that way WorkOrder will join to Asset (which you've already defined) and then you can join WorkOrderSpare to WorkOrder. I've also taken the liberty of removing parentheses on the joins, that's an Access thing.
SELECT CatalogueGroup.CatalogueGroupName,
Catalogue.CatalogueNumber,
Catalogue.CatalogueDescription,
Catalogue.CatalogueID,
Asset.IsActive,
WorkOrderSpare.WorkOrderSpareDescription,
WorkOrderSpare.ActualQuantity,
WorkOrderSpare.CreatedDateTime,
WorkOrder.WorkOrderNumber
FROM CatalogueGroup
INNER JOIN Catalogue ON CatalogueGroup.CatalogueGroupID = Catalogue.CatalogueGroupID
INNER JOIN Asset ON Catalogue.CatalogueID = Asset.CatalogueID
INNER JOIN WorkOrder ON Asset.AssetID = WorkOrder.AssetID
INNER JOIN WorkOrderSpare ON WorkOrder.WorkOrderID = WorkOrderSpare.WorkOrderID
I think you were close. As a slightly different approach to joining, try this:
SELECT CatalogueGroup.CatalogueGroupName,
Catalogue.CatalogueNumber,
Catalogue.CatalogueDescription,
Catalogue.CatalogueID,
Asset.IsActive,
WorkOrderSpare.WorkOrderSpareDescription,
WorkOrderSpare.ActualQuantity,
WorkOrderSpare.CreatedDateTime,
WorkOrder.WorkOrderNumber
FROM
CatalogueGroup, Catalogue, Asset, WorkOrder, WorkOrderSpare
WHERE CatalogueGroup.CatalogueGroupID = Catalogue.CatalogueGroupID
and Catalogue.CatalogueID = Asset.CatalogueID
and Asset.AssetID = WorkOrder.AssetID
and WorkOrder.WorkOrderID = WorkOrderSpare.WorkOrderID
It looks like it should work, but not having data, hard to know if simple joins all the way through is what you want. (It's a matter of personal preference whether to use the and clauses rather than the inner join syntax. While on style preferences, I like table aliases if supported, so FROM CatalogueGroup cg for example, so that you can refer to cg.CatalogueGroupID etc, rather than writing out the full table name every time.)
Ok. so the error that you noted in a comment
The multi-part identifier "WorkOrder.WorkOrderID" could not be bound
is usually when you have an alias for a table and instead of using alias in JOIN you use the table name or when you are using the wrong column name or table name.
Ideally in SQL server your query should look like this
SELECT
cg.CatalogueGroupName,
c.CatalogueNumber,
c.CatalogueDescription,
c.CatalogueID,
A.IsActive,
Wo.WorkOrderNumber,
WoS.WorkOrderSpareDescription,
WoS.ActualQuantity,
WoS.CreatedDateTime
FROM CatalogueGroup cg
INNER JOIN Catalogue c ON cg.CatalogueGroupID = c.CatalogueGroupID
INNER JOIN Asset A ON c.CatalogueID = A.CatalogueID
INNER JOIN WorkOrder Wo ON Wo.AssetID= A.AssetID
INNER JOIN WorkOrderSpare WoS ON Wo.WorkOrderID = WoS.WorkOrderID