What is the best way to write inner join query in SQL? - 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.

Related

Condition on main table in inner join vs in where clause

Is there any reason on an INNER JOIN to have a condition on the main table vs in the WHERE clause?
Example in INNER JOIN:
SELECT
(various columns here from each table)
FROM dbo.MainTable AS m
INNER JOIN dbo.JohnDataRecord AS jdr
ON m.ibID = jdr.ibID
AND m.MainID = #MainId -- question here
AND jdr.SentDate IS NULL
LEFT JOIN dbo.PTable AS p1
ON jdr.RecordID = p1.RecordID
LEFT JOIN dbo.DataRecipient AS dr
ON jdr.RecipientID = dr.RecipientID
(more left joins here)
WHERE
dr.lastRecordID IS NOT NULL;
Query with condition in WHERE clause:
SELECT
(various columns here from each table)
FROM dbo.MainTable AS m
INNER JOIN dbo.JohnDataRecord AS jdr
ON m.ibID = jdr.ibID
AND jdr.SentDate IS NULL
LEFT JOIN dbo.PTable AS p1
ON jdr.RecordID = p1.RecordID
LEFT JOIN dbo.DataRecipient AS dr
ON jdr.RecipientID = dr.RecipientID
(more left joins here)
WHERE
m.MainID = #MainId -- question here
AND dr.lastRecordID IS NOT NULL;
Difference in other similar questions that are more general whereas this is specific to SQL Server.
In the scope of the question,
Is there any reason on an INNER JOIN to have a condition on the main
table vs in the WHERE clause?
This is a STYLE choice for the INNER JOIN.
From a pure style reflection point of view:
While there is no hard and fast rule for STYLE, it is generally observed that this is a less often used style choice. For example that might generally lead to more challenging maintenance such as if someone where to remove the INNER JOIN and all the subsequent ON clause conditions, it would effect the primary table result set, OR make the query more difficult to debug/understand when it is a very complex set of joins.
It might also be noted that this line might be placed on many INNER JOINS further adding to the confusion.

Is there a option to clean this SQL query up

I was wondering if it was possible to make this query smaller
SELECT Templates.TempName
,TimeSpans.TimeSpan
,TemplateSlotTypes.[Type]
,TemplateSlots.Potition
,TemplateSlots.duration
FROM TimeSpans
INNER JOIN Templates ON Templates.TimeSpanId = TimeSpans.Id
INNER JOIN TemplateSlots ON Templates.Id = TemplateSlots.TemplateId
INNER JOIN TemplateSlotTypes ON TemplateSlots.[Type] = TemplateSlotTypes.Id
It seems that you need all the parts of this query, so there's nothing that can just be dropped from the query.
You could, however, use table aliases to reduce the amount of text:
SELECT t.TempName, tsp.TimeSpan, tst.[Type], ts.Potition, ts.duuration
FROM TimeSpans tsp
INNER JOIN Templates t ON t.TimeSpanId = tsp.Id
INNER JOIN TemplateSlots ts ON t.Id = ts.TemplateId
INNER JOIN TemplateSlotTypes tst ON ts.[Type] = tst.Id
Table aliases will make the joins less verbose, but assuming the field names are unique to the tables involved you don't need to prefix them with the table name.
SELECT TempName
,TimeSpan
,[Type]
,Potition
,duration
FROM TimeSpans ts
INNER JOIN Templates t ON t.TimeSpanId = ts.Id
INNER JOIN TemplateSlots s ON t.Id = s.TemplateId
INNER JOIN TemplateSlotTypes st ON s.[Type] = st.Id
However, I would recommend the use of a good IDE for SQL query development where it performs the joins for you and removes a lot of the typing.
Manually reducing the amount of text in a query is a false economy in the long run. It can actually make the SQL harder to read, and therefore more time consuming to modify or debug in the future.

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;

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

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.

SQL: Chaining Joins Efficiency

I have a query in my WordPress plugin like this:
SELECT users.*, U.`meta_value` AS first_name,M.`meta_value` AS last_name
FROM `nwp_users` AS users
LEFT JOIN `nwp_usermeta` U
ON users.`ID`=U.`user_id`
LEFT JOIN `nwp_usermeta` M
ON users.`ID`=M.`user_id`
LEFT JOIN `nwp_usermeta` C
ON users.`ID`=C.`user_id`
WHERE U.meta_key = 'first_name'
AND M.meta_key = 'last_name'
AND C.meta_key = 'nwp_capabilities'
ORDER BY users.`user_login` ASC
LIMIT 0,10
I'm new to using JOIN and I'm wondering how efficient it is to use so many JOIN in one query. Is it better to split it up into multiple queries?
The database schema can be found here.
JOIN usually isn't so bad if the keys are indexed. LEFT JOIN is almost always a performance hit and you should avoid it if possible. The difference is that LEFT JOIN will join all rows in the joined table even if the column you're joining is NULL. While a regular (straight) JOIN just joins the rows that match.
Post your table structure and we can give you a better query.
See this comment:
http://forums.mysql.com/read.php?24,205080,205274#msg-205274
For what it's worth, to find out what MySQL is doing and to see if you have indexed properly, always check the EXPLAIN plan. You do this by putting EXPLAIN before your query (literally add the word EXPLAIN before the query), then run it.
In your query, you have a filter AND C.meta_key = 'nwp_capabilities' which means that all the LEFT JOINs above it can be equally written as INNER JOINs. Because if the LEFT JOINS fail (LEFT OUTER is intended to preserve the results from the left side), the result will 100% be filtered out by the WHERE clause.
So a more optimal query would be
SELECT users.*, U.`meta_value` AS first_name,M.`meta_value` AS last_name
FROM `nwp_users` AS users
JOIN `nwp_usermeta` U
ON users.`ID`=U.`user_id`
JOIN `nwp_usermeta` M
ON users.`ID`=M.`user_id`
JOIN `nwp_usermeta` C
ON users.`ID`=C.`user_id`
WHERE U.meta_key = 'first_name'
AND M.meta_key = 'last_name'
AND C.meta_key = 'nwp_capabilities'
ORDER BY users.`user_login` ASC
LIMIT 0,10
(note: "JOIN" (alone) = "INNER JOIN")
Try explaining the query to see what is going on and if your select if optimized. If you haven't used explain before read some tutorials:
http://www.learn-mysql-tutorial.com/OptimizeQueries.cfm
http://www.databasejournal.com/features/mysql/article.php/1382791/Optimizing-MySQL-Queries-and-Indexes.htm