When to open and close brackets surrounding joins in MS Access SQL - sql

I want to understand when to open and close brackets when representing joins in MS Access queries as I am developing a query builder using C++ for MS Access queries so that I can apply the same code to generate similar queries.
SELECT
MasterTool.Name, Toolsets.SlaveToolID, Tools.MachineID
FROM
Tools AS MasterTool
LEFT JOIN
(
Toolsets LEFT JOIN Tools ON Toolsets.SlaveToolID = Tools.ID
)
ON MasterTool.ID = Toolsets.MasterToolID
Edit:
#LeeMac as per your explaination when i modified the query which i presented earlier to this
SELECT Tools.Name, Toolsets.SlaveToolID, Tools.MachineID FROM (Tools
LEFT JOIN Toolsets ON Toolsets.SlaveToolID = Tools.ID )
LEFT JOIN Tools ON Toolsets.MasterToolID = Tools.ID
i am getting error Join Expression Not Supported is there is any simple way to write the above query.

Essentially, when an MS Access query references more than two tables, every successive join between a pair of tables should be nested within parentheses.
For example, a query with two tables requires no parentheses:
select *
from a inner join b on a.id = b.id
The addition of a third joined table necessitates parentheses surrounding the original join in order to distinguish it from the additional join:
select *
from
(
a inner join b on a.id = b.id
)
inner join c on a.id = c.id
Every successive addition of a table will then cause the existing joins to be nested within another level of parentheses:
select *
from
(
(
a inner join b on a.id = b.id
)
inner join c on a.id = c.id
)
inner join d on a.id = d.id
Hence, in general:
select *
from
(
(
(
(
table1 [inner/left/right] join table2 on [conditions]
)
[inner/left/right] join table3 on [conditions]
)
[inner/left/right] join table4 on [conditions]
)
...
)
[inner/left/right] join tableN on [conditions]
There is a subtlety where LEFT/RIGHT joins are concerned, in that the order of nesting must maintain the direction of the join, for example:
select *
from
(
c left join b on c.id = b.id
)
left join a on a.id = b.id
Could be permuted to:
select *
from
c left join
(
b left join a on b.id = a.id
)
on c.id = b.id

Related

Pull columns from series of joins in SQL

I am kind of stuck at one problem at my job where I need to pull 2 cols from base table and 1 column from a series of joins.
Please note that, I can not provide real data so I am using dummy column/table names and there are 100s of columns in real project.
Select A.Name,B.Age, D.Sal
From A Left join B on A.iD=B.id and B.Date=CURRENT_DATE
(/* join A and B table and return distinct column which is B.XYZ)
inner join C on C.iD=B.XYZ
(/* join B and C take C.YYY column for next join */)
inner join D on D.id=C.YYY
(/* Take out the D.Sal column from this join */) where A.Dept='IT'
I have written this query but it is taking forever to run because B.XYZ column has a lot of duplicates. how can I get distinct of B.XYZ column from that join.
For Joining Table B, you first get a distinct table of the columns you need from B then join.
SELECT
A.Name,
B.Age,
D.Sal
From A
LEFT JOIN ( -- Instead of all cols (*), just id, Date, Age and xyz might do
SELECT DISTINCT * FROM B
) B ON A.iD = B.id AND B.Date = CURRENT_DATE
--(/* join A and B table and return distinct column which is B.XYZ */)
INNER JOIN C ON C.iD = B.XYZ
--(/*join B and C take C.YYY column for next join */)
INNER JOIN D ON D.id = C.YYY
--(/* Take out the D.Sal column from this join */)
WHERE A.Dept='IT'
You say you get the same rows multifold, because for a b.id, date and age you get the same xyz more than once, or so I understand it.
One option is to join with a subquery that gets the distinct data:
SELECT a.name, b.age, d.sal
FROM a
LEFT JOIN
(
SELECT DISTINCT id, date, age, xyz FROM b
) dist_b ON dist_b.id = a.id and dist_b.date = CURRENT_DATE
INNER JOIN c ON c.id = dist_b.xyz
INNER JOIN d ON d.id = c.yyy
WHERE a.dept = 'IT';
Of course you can even move the date condition inside the subquery:
SELECT a.name, b.age, d.sal
FROM a
LEFT JOIN
(
SELECT DISTINCT id, age, xyz FROM b WHERE date = CURRENT_DATE
) dist_b ON dist_b.id = a.id
INNER JOIN c ON c.id = dist_b.xyz
INNER JOIN d ON d.id = c.yyy
WHERE a.dept = 'IT';
Your LEFT OUTER JOIN doesn't work by the way. As you are inner joining the following tables, a match must exists, so your outer join becomes an inner join. For the outer join to work you would have to outer join the following tables, too.

MS Acces Jet SQL Error: Join Expression not supported with multiple Join conditions

I'm trying to run this SQL Expression in Access:
Select *
From ((TableA
Left Join TableB
On TableB.FK = TableA.PK)
Left Join TableC
On TableC.FK = TableB.PK)
Left Join (SELECT a,b,c FROM TableD WHERE b > 1) AS TableD
On (TableD.FK = TableC.PK AND TableA.a = TableD.a)
but it keeps getting error: Join-Expression not supported.
Whats the problem?
Sorry, im just starting with Jet-SQL and in T-SQL its all fine.
Thanks
The issue is that the final outer join condition TableA.a = TableD.a will cause the query to contain ambiguous outer joins, since the records to which TableA is joined to TableD will depend upon the results of the joins between TableA->TableB, TableB->TableC and TableC->TableD.
To avoid this, you'll likely need to structure your query with the joins between tables TableA, TableB & TableC existing within a subquery, the result of which is then outer joined to TableD. This unambiguously defines the order in which the joins are evaluated.
For example:
select * from
(
select TableA.a, TableC.PK from
(
TableA left join TableB on TableA.PK = TableB.FK
)
left join TableC on TableB.PK = TableC.FK
) q1
left join
(
select TableD.a, TableD.b, TableD.c, TableD.FK from TableD
where TableD.b > 1
) q2
on q1.a = q2.a and q1.PK = q2.FK
Consider relating every join to the FROM table to avoid having to nest relations.
SELECT *
FROM ((TableA
LEFT JOIN TableB
ON TableB.FK = TableA.PK)
LEFT JOIN TableC
ON TableC.FK = TableA.PK)
LEFT JOIN
(SELECT FK,a,b,c
FROM TableD WHERE b > 1
) AS TableD
ON (TableD.FK = TableA.PK)
AND (TableD.a = TableA.a)

Select and update on the rows in a table by using joins multiple table in SQL Server

I am trying to update 1.2 million rows in a table that had data inserted kind of incorrectly via legacy application. I am not very good at writing efficient SQL queries as I am experiencing these sort of larger set of data for the first time.
I have written query as below and it's taking a very long time to run this query. I have commented out my update logic in the statement.
SELECT T1.Old_id,
T1. Report_id,
T2.New_id /* update a set file_id = T2.new_id*/
FROM
(SELECT A.File_id AS Old_id,
A.Id AS Report_id,
A.User_id AS USER
FROM A
INNER JOIN B ON A.Id = B.A_id
INNER JOIN C ON B.Id = C. B_id
INNER JOIN D ON C.Id = D.C_id
INNER JOIN E ON D.Id = E.D_id
WHERE E.Name = 'student_report') AS T1
LEFT JOIN
(SELECT Max(C.Report_id) AS New_id,
C.Created_by AS User_id
FROM C
INNER JOIN D ON C.Id = D.C_id
INNER JOIN E ON D.Id = E.D_id
WHERE E.Name = 'teacher_report'
GROUP BY C.Created_by) ON T1.User_id = T2.User_id /* where a.id = T1.report_id*/
I need to update the file_id in table a by the report_id of c. With a small set of data, the select query works fine and gives the result as intended. But on the server where it has 1.2 million rows, it takes extremely long time.
Is there a way we could put those two sub-queries into one and make it work for 'update' as well? Because, update also fails as it has 'group by' on the second sub-query.
Main problem is using Subquery in join condition.
Second problem,when same resultset is to be use multiple time then you should put common resultset in CTE or #temp table.
create table #temp(B_id int,cTeport_id int,cUserID int,EName varchar(100))
insert into #temp
select B_id,C.Report_id,C.Created_by,E.Name
INNER JOIN C ON B.Id = C. B_id
INNER JOIN D ON C.Id = D.C_id
INNER JOIN E ON D.Id = E.D_id
WHERE E.Name in( 'teacher_report','student_report')
;With CTE as
(
SELECT Max(C.Report_id) AS New_id,
C.Created_by AS User_id
FROM #temp c
WHERE c.Name = 'teacher_report'
GROUP BY C.Created_by
)
SELECT T1.Old_id,
T1. Report_id,
T2.New_id /* update a set file_id = T2.new_id*/
FROM
(SELECT A.File_id AS Old_id,
A.Id AS Report_id,
A.User_id AS USER
FROM A
INNER JOIN B ON A.Id = B.A_id
INNER JOIN #temp t ON B.Id = t. B_id
WHERE t.Name = 'student_report'
and exists(select 1 from cte t1 T1.User_id = T.User_id)
My script is not Tested so you can fix any minor bug if any.
In Temp table carefully define all columns which is require for this query along with their datatype.
Please analyze the Query cost by using Execution Plan. Check the table which is making delay then check proper Indexing used for that particular table or not.

Access SQL - Joins on multple tables

I have come across a Join Error in Access SQL, when using multiple "ON" criteria's. I am unable to perform an ON clause on 2 different tables, for example:
select *
from
(((A
left join B on a.id = b.id)
left join c on c.id = b.id)
left join D
on (d.id = b.id) and (d.id = a.id)
That final join statement causes an error because I link table D on table B first, and then link Table D on Table A. If I choose to instead link table D on Table B again, then it resolves. However, I need to join it this way due to the certain data I need to link Table D on from both tables.
How can I more efficiently structure my query to achieve my results?
you may try this select * from A left join B on a.id = b.id left join c on c.id = b.id left join D on d.id = b.id and d.id = a.id
It's somewhat difficult to tell what you're trying to do exactly, but most likely, this is what you want:
select *
from
(((A
left join B on a.id = b.id)
left join C on c.id = b.id)
left join D on d.id = a.id)
Since you're trying a LEFT JOIN, there is no reason to link multiple ids to eachother.

How to use oracle outer join with a filter where clause

If i write a sql:
select *
from a,b
where a.id=b.id(+)
and b.val="test"
and i want all records from a where corresponding record in b does not exist or it exists with val="test", is this the correct query?
You're much better off using the ANSI syntax
SELECT *
FROM a
LEFT OUTER JOIN b ON( a.id = b.id and
b.val = 'test' )
You can do the same thing using Oracle's syntax as well but it gets a bit hinkey
SELECT *
FROM a,
b
WHERE a.id = b.id(+)
AND b.val(+) = 'test'
Note that in both cases, I'm ignoring the c table since you don't specify a join condition. And I'm assuming that you don't really want to join A to B and then generate a Cartesian product with C.
Move the condition into the JOIN clause and use the ANSI standard join pattern.
SELECT NameYourFields,...
FROM A
LEFT OUTER JOIN B
ON A.ID = B.ID
AND B.VAL = 'test'
INNER JOIN C
ON ...
A LEFT OUTER JOIN is one of the JOIN operations that allow you to specify a join clause. It preserves the unmatched rows from the first (left) table, joining them with a NULL row in the shape of the second (right) table.
So you can do as follows :
SELECT
FROM a LEFT OUTER JOIN b
ON a.id = b.id
--Note that you have used double quote "test" which is not used for varchar in SQL you should use single quote 'test'
AND b.val = 'test';
SELECT * FROM abc a, xyz b
WHERE a.id = b.id
AND b.val = 'test'