Nested SQL Joins in MS Access 2013 - sql

I normalized my data and have been trying to display data across multiple tables. I'm fairly new to SQL, so please bear with me.
What I'm trying to do is display tasks that haven't been assigned to a project yet, but contain data from various tables such as project title, company, etc (Using a LEFT JOIN and a WHERE clause).
The original code which works:
SELECT Tasks.ID, Projects_Tasks.ProjectID
FROM Tasks LEFT JOIN Projects_Tasks ON Projects_Tasks.TaskID = Tasks.ID
WHERE Projects_Tasks.ProjectID IS NULL;
The nested joins code (that doesn't work):
SELECT Tasks.ID, Projects.ProjectTitle, ProjectManagers.FirstName, ProjectManagers.LastName, Companies.Company
FROM ((((Tasks
LEFT JOIN Projects_Tasks ON Projects_Tasks.TaskID = Tasks.ID)
INNER JOIN Projects_Tasks ON Projects_Tasks.ID = Projects.ID)
INNER JOIN Projects ON Projects.ID = Projects_Tasks.ProjectID)
INNER JOIN ProjectManagers ON ProjectManagers.ID = Projects.ProjectManagerID)
INNER JOIN Companies ON Companies.ID = ProjectManagers.CompanyID
WHERE Projects_Tasks.ProjectID IS NULL;
I've tried numerous combinations, but I just can't get it to work. I've tried reversing the order of my nested joins (in case it executes from bottom to top) and I've tri

I don't enjoy writing SQL statements.The good thing about Access though is it can make your SQL statements for you in Queries
Using Query Builder:
Select the tables Project_Tasks & Project_Managers & all other tables
you want to display data
Select all the relevant data fields you want to display
Where you have the 'ProjectID' field, the Criteria section needs to have "Is Null" (don't put the quotation marks though)
Then, save the query, and run it. (You can probably just use that query, or otherwise strip out the SQL statement)
Good luck!

Related

Access SQL subquery access field from parent

I have a SQL query that works in Access 2016:
SELECT
Count(*) AS total_tests,
Sum(IIf(score>=securing_threshold And score<mastering_threshold,1,0)) AS total_securing,
Sum(IIf(score>=mastering_threshold,1,0)) AS total_mastering,
total_securing/Count(*) AS percent_securing,
total_mastering/Count(*) AS percent_mastering,
(Count(*)-total_securing-total_mastering)/Count(*) AS percent_below,
subjects.subject,
students.year_entered,
IIf(Month(Date())<9,Year(Date())-students.year_entered+6,Year(Date())-students.year_entered+7) AS current_form,
groups.group
FROM
((subjects
INNER JOIN tests ON subjects.ID = tests.subject)
INNER JOIN (students
INNER JOIN test_results ON students.ID = test_results.student) ON tests.ID = test_results.test)
LEFT JOIN
(SELECT * FROM group_membership LEFT JOIN groups ON group_membership.group = groups.ID) As g
ON students.ID = g.student
GROUP BY subjects.subject, students.year_entered, groups.group;
However, I wish to filter out irrelevant groups before joining them to my table. The table groups has a column subject which is a foreign key.
When I try changing ON students.ID = g.student to ON students.ID = g.student And subjects.ID = g.subject I get the error 'JOIN expression not supported'.
Alternatively, when I try adding WHERE subjects.ID = groups.subject to the subquery, it asks me for the parameter value of subjects.ID, although it is a column in the parent query.
Googling reveals many similar errors but they were all resolved by changing the brackets. That didn't help.
Just in case the table relationships help:
Thank you.
EDIT: Sample database at https://www.dropbox.com/s/yh80oooem6gsni7/student%20tracker.ACCDB?dl=0
MS Access queries with many joins are difficult to update by SQL alone as parenetheses pairings are required unlike other RDBMS's and these pairings must follow an order. Moreover, some pairings can even be nested. Hence, for beginners it is advised to build queries with complex and many joins using the query design GUI in the MS Office application and let it build out the SQL.
For a simple filter on the g derived table, you could filter subject on the derived table, g, but likely you want want all subjects:
...
(SELECT * FROM group_membership
LEFT JOIN groups ON group_membership.group = groups.ID
WHERE groups.subject='Earth Science') As g
...
So for all subjects, consider re-building query from scratch in GUI that nearly mirrors your table relationships which actually auto-links joins in the GUI. Then, drop unneeded tables.
Usually you want to begin with the join table or set like groups and group_membership or tests and test_results. In fact, consider saving the g derived table as its own query.
Then add the distinct record primary source tables like students and subjects.
You may even need to play around with order in FROM and JOIN clauses to attain desired results, and maybe even add the same table in query. And be careful with adding join tables like group_membership (two one-to-many links), to GROUP BY queries as it leads to the duplicate record aggregation. So you may need to join aggregates queries by subject.
Unless you can post content of all tables, from our perspective it is difficult to help from here.
Your subquery g uses a LEFT JOIN, but there is a enforced 1:n relation between the two tables, so there will always be a matching group. Use a INNER JOIN instead.
With g.subject you are trying to join on a column that is on the right side of a left join, that cannot really work.
Also you shouldn't use SELECT * on a join of tables with identical column names. Include only the qualified column names that you need.
LEFT JOIN
(SELECT group_membership.student, groups.group, groups.subject
FROM group_membership INNER JOIN groups
ON group_membership.group = groups.ID) As g
ON (students.ID = g.student AND subjects.ID = g.subject)
I would call the columns in group_membership group_ID and student_ID to avoid confusion.
I don't have the database to test, but I would use subject table as subquery:
(SELECT * FROM subject WHERE filter out what you don't need) Subj
Then INNER JOIN this new Subj Table in your query which would exclude irrelevant groups.
Also I would never create join in WHERE clause (WHERE subjects.ID = groups.subject), what this does it creates cartesian product (table with all the possible combinations of subjects.ID and groups.subject) then it filters out records to satisfy your join. When dealing with huge data it might take forever or crash.
Error related to "Join expression may not be supported"; do datatypes match in those fields?
I solved it by (a lot of trial and error and) taking the advice here to make queries in the GUI and joining them. The end result is 4 queries deep! If the database was bigger, performance would be awful... but now its working I can tweak it eventually.
Thank you everybody!

SQL Statement for Accessing Data from Multiple Tables

I have 7 Tables as per attached following Image.
I will either enter Engine Number or Chassis Number and it should show the respective tables information (these tables have only mentioned fields) so all fields can be shown as result.
I can use hard coded Engine Number or Chassis Number. Every time of execution of this Query, I will hard code the required Engine/Chassis Number and will get the result.
Can anybody please help me to write this query for me?
Click Here to See the Tables
This might be a starting point for your solution.
SELECT prod.EngineNo AS engNo, prod.ChassisNo, doral.doralNo [, table.column [AS name]]
FROM DOProductSpecsDetais AS prod
INNER JOIN DORAL AS doral
ON prod.DOProductSpecsDetailID = doral.DOProductSpecsID
INNER JOIN DOProductDetail AS prodDetail
ON prod.DOProductDetailID = prodDetail.DOProductDetailID
WHERE prod.ChassisNo = '<input>' OR prod.EngineNo='<input>'
Between the SELECT and the FROM Statement, you can select any column out of your JOIN.
You can cascade as many JOINs as you like...
Which DBMS are you going to use?
One suggestion: Try to simplify the names of your columns, if possible.
One more: If you just started to do Database things, it is always helpful to start a test environment and use a client tool.
You can write query something like this:
select * from
DoProductSpecsDetail tbl1 inner join Doral tbl2
on tbl1.DoProductSpecsDetailId = tbl2.DoProductSpecsId
inner join DoproductDetail tbl3
on tbl1.DoProductDetailId = tbl3.DoProductDetailId
inner join ProductColor tbl4
on tbl1.ProductColorId = tbl4.ProductColorId
inner join DoDetail tbl5
on tbl3.DeliveryOrderDetailId = tbl5.DeliveryOrderId
inner join ProductMain tbl6
on tbl3.ProductId = tbl6.ProductId
inner join BPMain tbl7
on tbl5.BusinessPartnerId = tbl7.BusinessPartnerId

Is it possible to detect where the join fails on a certain record?

Please bear with me as this may be a question without a possible answer, but I hope I describe it correctly..
I have a query which joins a number of tables and produces results, and here is the SQL:
SELECT
dbo.Property.PropertyPK,
dbo.Tenancy.TenancyPK,
dbo.Tenant.ContactFK,
dbo.Contacts.strTitle,
dbo.Contacts.strFirstName,
dbo.Contacts.strSurname
FROM dbo.Property
INNER JOIN dbo.Tenancy ON dbo.Property.PropertyPK = dbo.Tenancy.PropertyFK
INNER JOIN dbo.Tenant ON dbo.Tenancy.TenancyPK = dbo.Tenant.TenancyFK
INNER JOIN dbo.Contacts ON dbo.Tenant.ContactFK = dbo.Contacts.ContactPK
The main table is the Property table and I filter out one row by specifying a PropertyPK in my criteria..
My question is.. If the Tenant or Contact record does not exist and I run my query in SQL Management Studio of course I get a message saying there are no rows but can I determine at what stage the join has failed between two tables?
I can of course check this in management studio but I am trying to help the user on the application side to inform them of why there are no rows. My application is in VB and I will write that check if there are no rows and I cannot determine it in SQL..
Sorry for the question in advance..
Derek.. :)
Simply use a LEFT JOIN:
SELECT p.PropertyPK, ty.TenancyPK, t.ContactFK,
c.strTitle, c.strFirstName, c.strSurname
FROM dbo.Property p LEFT JOIN
dbo.Tenancy ty
ON p.PropertyPK = ty.PropertyFK LEFT JOIN
dbo.Tenant t
ON ty.TenancyPK = t.TenancyFK LEFT JOIN
dbo.Contacts c
ON t.ContactFK = c.ContactPK;
This will keep all rows in the Property table. You can then see which primary keys are NULL to see if there were matches in the other tables.
Note that the query is much easier to write and to read when you use table aliases.

Join three tables and display in gridview as per condition

In my Access database I am trying to display data from three tables:
PERS
COURSE
WORKED
I want all rows from PERS and some matching fields from COURSE and WORKED. KNO is the common field in all tables
eg : SELECT [KNO], [Name], [Company], [Location], [State] FROM [Pers]
If the KNo had done CCNA (Course.Qualification)
if he had Worked in Channai or Kolkatta or in Bangalore (Worked.Coyloc)
then only show
I used :
Select
Pers.KNO, Pers.Name, Pers.Company, Pers.Location, Pers.State
from Pers
left join (Course on pers.KNo=Course.KNO)
left join Worked.KNo=Per.KNO
where
Course.Qualification='CCNA'
and (Worked.Coyloc='Bangalore' or Worked.Coyloc='Channai or Worked.Coyloc='Kolkatta')
I am having trouble adding the [Worked] table to the query. When I just include [Pers] and [Course] I get the results I expect.
Select
Pers.KNO, Pers.Name, Pers.Company, Pers.Location, Pers.State
from Pers
left join Course
on pers.KNo=Course.KNO
where
Course.Qualification='CCNA'
If you are having trouble writing a query sometimes it is helpful to mock it up using the Query Designer in Access and then see what SQL it produces. For your query:
switching to SQL View reveals the following (reformatted for clarity):
SELECT Pers.KNO, Pers.Name, Pers.Company, Pers.Location, Pers.State
FROM
(
Pers
LEFT JOIN
Course
ON Pers.KNO = Course.KNO
)
LEFT JOIN
Worked
ON Pers.KNO = Worked.KNO
WHERE (((Course.Qualification)="CCNA") AND ((Worked.Coyloc)="Bangalore"))
OR (((Course.Qualification)="CCNA") AND ((Worked.Coyloc)="Channai"))
OR (((Course.Qualification)="CCNA") AND ((Worked.Coyloc)="Kolkatta"));
Note that the parentheses in the FROM clause are important. Access is a bit fussy about that.
Other notes:
As you may have noticed, the WHERE clause could be reorganized as
WHERE Course.Qualification="CCNA"
AND (Worked.Coyloc="Bangalore" OR Worked.Coyloc="Channai" OR Worked.Coyloc="Kolkatta")
Also, since you have specific WHERE conditions on columns in both the [Course] and [Worked] tables then you don't really need to use LEFT JOINs. INNER JOINs would have sufficed.

Group by in SQL Server giving wrong count

I have a query which works, goes like this:
Select
count(InsuranceOrderLine.AntallPotensiale) as potensiale,
COUNT(InsuranceOrderLine.AntallSolgt) as Solgt,
InsuranceProduct.Name,
InsuranceProductCategory.Name as Kategori
From
InsuranceOrderLine, InsuranceProduct, InsuranceProductCategory
where
InsuranceOrderLine.FKInsuranceProductId = InsuranceProduct.InsuranceProductID
and InsuranceProduct.FKInsuranceProductCategory = InsuranceProductCategory.InsuranceProductCategoryID
Group by
InsuranceProduct.name, InsuranceProductCategory.Name
This query over returns what I need, but when I try to add more table (InsuranceOrder) to be able to get the regardingUser column, then all the count values are way high.
Select
count(InsuranceOrderLine.AntallPotensiale) as Potensiale,
COUNT(InsuranceOrderLine.AntallSolgt) as Solgt,
InsuranceProduct.Name,
InsuranceProductCategory.Name as Kategori,
RegardingUser
From
InsuranceOrderLine, InsuranceProduct, InsuranceProductCategory, InsuranceSalesLead
where
InsuranceOrderLine.FKInsuranceProductId = InsuranceProduct.InsuranceProductID
and InsuranceProduct.FKInsuranceProductCategory = InsuranceProductCategory.InsuranceProductCategoryID
Group by
InsuranceProduct.name, InsuranceProductCategory.Name,RegardingUser
Thanks in advance
You're adding one more table to your FROM statement, but you don't specify any JOIN condition for that table - so your previous result set will do a FULL OUTER JOIN (cartesian product) with your new table! Of course you'll get duplication of data....
That's one of the reasons that I'm recommending never to use that old, legacy style JOIN - do not simply list a comma-separated bunch of tables in your FROM statement.
Always use the new ANSI standard JOIN syntax with INNER JOIN, LEFT OUTER JOIN and so on:
SELECT
count(iol.AntallPotensiale) as Potensiale,
COUNT(iol.AntallSolgt) as Solgt,
ip.Name,
ipc.Name as Kategori,
isl.RegardingUser
FROM
dbo.InsuranceOrderLine iol
INNER JOIN
dbo.InsuranceProduct ip ON iol.FKInsuranceProductId = ip.InsuranceProductID
INNER JOIN
dbo.InsuranceProductCategory ipc ON ip.FKInsuranceProductCategory = ipc.InsuranceProductCategoryID
INNER JOIN
dbo.InsuranceSalesLead isl ON ???????? -- JOIN condition missing here !!
When you do this, you first of all see right away that you're missing a JOIN condition here - how is this new table InsuranceSalesLead linked to any of the other tables already used in this SQL statement??
And secondly, your intent is much clearer, since the JOIN conditions linking the tables are where they belong - right with the JOIN - and don't clutter up your WHERE clauses ...
It looks like you added the table join which slightly multiplies count of rows - make sure, that you properly joining the table. And be careful with aggregate functions over several joined tables - joins very often lead to duplicates