Having trouble converting SQL query to Access - sql-server

I have this query which works fine in SQL Server, but not in Access, and I'm having trouble converting it. I've always heard that JET is missing some TSQL features, and I suppose complex joins is one of them.
SELECT C.[Position], TT.[Description] as TrainingType, T.ProgramTitle, T.ProgramSubTitle, T.ProgramCode, ET.CompletedDate
from HR_Curriculum C
LEFT JOIN HR_Trainings T ON C.TrainingID = T.TrainingID
LEFT JOIN HR_TrainingTypes TT ON T.TrainingTypeID = TT.TrainingTypeID
LEFT JOIN HR_EmployeeTrainings ET ON C.TrainingID = ET.TrainingID
AND (ET.AvantiRecID IS NULL OR ET.AvantiRecID = '637')
where ( c.[Position] = 'Customer Service Representative'
OR C.[Position] = 'All Employees')
order by [Position], Description, ProgramTitle
I tried putting the extra join clause down in the WHERE clause, but for some reason this does not yield the proper count of records.

When you have more than one JOIN in ms-access you need to wrap them with parenthesis like this:
SELECT C.[Position], TT.[Description] as TrainingType, T.ProgramTitle, T.ProgramSubTitle, T.ProgramCode, ET.CompletedDate
from (((HR_Curriculum C
LEFT JOIN HR_Trainings T ON C.TrainingID = T.TrainingID)
LEFT JOIN HR_TrainingTypes TT ON T.TrainingTypeID = TT.TrainingTypeID)
LEFT JOIN HR_EmployeeTrainings ET ON C.TrainingID = ET.TrainingID
AND (ET.AvantiRecID IS NULL OR ET.AvantiRecID = '637'))
where ( c.[Position] = 'Customer Service Representative'
OR C.[Position] = 'All Employees')
order by [Position], Description, ProgramTitle
or you will have the Missing Operator error

Check that your table alias are delacred with 'as'. Access doesn't like [tablename] [alias], instead try [tablename] as [alias]. I know the complex left joins shouldn't be a problem, but Access might be choking an the alias delcarations if it's returning some join error. I would also try quering out the restriction on the ET table, and then joining that to the larger query. I've noticed that trying to put restrictions on records involved in left or right joins will often not produce the correct records as Access will limit the set after the join.

Related

View slows down when I add additional conditions in where clause when querying the view

I am using a similar query. I cannot post the actual query and the execution plans here. I tried adding an execution plan suggesting a non-clustered index but it slowed down the query further.
I know it's incomplete information, but can you please suggest what I can try please? I am out of options!!
I am putting the below condition in the where clause, the date seems fine but as soon as I add any of the other 2, the query takes hours. The where condition is used when I try to query the view.
where Date_Time between '2021-11-01 00:00:00.000' and '2022-11-02 00:00:00.000'
and Visit_code not in ('12', '13')
and mode_code <>'99'
Execution plan XML
CREATE VIEW [dbo].[vw_Test] AS
select fields
from table1 ed
left join table2 e on ed.field1_id = e.field1_id
left join table3 et on et.field1_id = ed.field1_id
left join table4 etf on etf.field1_id = e.field1_id
and etf.field2_cd= 85429041
and etf.dt_tm_field >= '2025-01-01 00:00:00.0000000'
left join table5 etf_dt on etf_dt.field1 = e.field1
and etf_dt.field3= 85429039
and etf_dt.dt_tm_field >= '2025-01-01 00:00:00.0000000'
left join table6 ei on ei.field1 = ed.field1
and ei.field4_cd = 123485.00
left join table7 cvo_ModeOfArrival on cvo_ModeOfArrival.field = ed.field6
and cvo_ModeOfArrival.field5 = 12345
left join table7 cvo_ModeOfSep on cvo_ModeOfSep.field = ei.field7
and cvo_ModeOfSep.field5 = 23456
left join table7 cvo_FinancialClass on cvo_FinancialClass.field = e.field8
and cvo_FinancialClass.field5 = 34567
left join table7 cvo_Specialty on cvo_Specialty.field = e.field9
and cvo_Specialty.field5 = 45678
left join table8 ea on ea.field1_id = e.field1_id
left join table7 cvo_ea on cvo_ea.field = ea.field10
and cvo_ea.field11 = 345666
GO
Looking at your code I can't see anything that can be improved in the context of T-SQL statement.
I will advice the following:
check each table and which columns you need in the fields part - it is possible the engine to be reading the whole row, instead the needed columns as index is missing; you can create nonclustered indexes in order to reduce the IO
check if any of these new indexes can be filtered index, as you have a lot of hard coded criteria (ei.field4_cd = 123485.00)
If the above is not enough, you may think of creating separate table for storing this information and populate it in advanced.
In order to debug, you can add the following line before the query:
SET STATISTICS IO ON;
and then past the results from the messages tab here - it will give you some details about for which tables most IO is consumed. You can start with them.
I would investigate breaking this query into multiple parts using derived tables. There are plenty of examples for this online. I always try to use SELECT TOP (2147483647) ....

MS SQL Server trouble with JOIN

I'm new to SQL and need a push in the right direction.
I currently have a working SQL query accessing 3 tables in a database, and I need to add a JOIN using a 4th table, but the syntax escapes me. To simplify, what I have now is:
SELECT
t1_col1, t1_col2, t2_col1, t2_col2, t3_col1
FROM
table1, table2, table3
WHERE
{some conditions}
ORDER BY
t1_col1 ASC;
What I need to do is to add a LEFT OUTER JOIN selecting 2 columns from table4 and have ON t1_field1 = t4_field1, but whatever I try, I'm getting syntax errors all over the place. I don't seem to understand the correct syntax.
I tried
SELECT *
FROM table1
LEFT OUTER JOIN table2;
which has no errors, but as soon as I start SELECTing columns and adding conditions, I get stuck.
I would greatly appreciate any assistance with this.
You do not specify the join criteria. Those would be in your WHERE clause under "some conditions". So, I will make up so that I can show syntax. The syntax you show is often termed "old". It has been discouraged for 15 years or more in the SQL Server documentation. Microsoft consistently threatens to stop recognizing the syntax. But, apparently they have not followed through on that threat.
The syntax errors you are getting occur because you are mixing the old style joins (comma separated with WHERE clause) with the new style (LEFT OUTER JOIN) with ON clauses.
Your existing query should be changed to something like this. The tables are aliased because it makes it easier to read and is customary. I just made up the JOIN criteria.
SELECT t1_col1, t1_col2, t2_col1, t2_col2, t3_col1
FROM table1 t1
INNER JOIN table2 t2 ON t2.one_ID = t1.one_ID
INNER JOIN table3 t3 ON t3.two_ID = t2.two_ID
LEFT OUTER JOIN table4 t4 ON t4.three_ID = t3.three_ID
I hope that helps with "a push in the right direction."
You may also want to read this post that explains the different ways to join tables in a query. What's the difference between INNER JOIN, LEFT JOIN, RIGHT JOIN and FULL JOIN?
Also for the record the "OLD STYLE" of joining tables (NOT RECOMMENDED) would look like this (but do NOT do this - it is a horrible way to write SQL). And it does not work for left outer joins. Get familiar with using the ...JOIN...ON... syntax:
SELECT t1_col1, t1_col2, t2_col1, t2_col2, t3_col1
FROM table1 t1, table2 t2, table3 t3
LEFT OUTER JOIN table4 t4 ON t4.three_ID = t3.three_ID
WHERE
t2.one_ID = t1.one_ID
AND t3.two_ID = t2.two_ID

Is it possible to perform a join in Access on a second column if the first is blank?

I have this ugly source data with two columns, let's call them EmpID and SomeCode. Generally EmpID maps to the EmployeeListing table. But sometimes, people are entering the Employee IDs in the SomeCode field.
The person previously running this report in Excel 'solved' this problem by performing multiple vlookups with if statements, as well as running some manual checks to ensure results were accurate. As I'm moving these files to Access I am not sure how best to handle this scenario.
Ideally, I'm hoping to tell my queries to do a Left Join on SomeCode if EmpID is null, otherwise Left Join on EmpID
Unfortunately, there's no way for me to force validation or anything of the sort in the source data.
Here's the full SQL query I'm working on:
SELECT DDATransMaster.Fulfillment,
DDATransMaster.ConfirmationNumber,
DDATransMaster.PromotionCode,
DDATransMaster.DirectSellerNumber,
NZ([DDATransMaster]![DirectSellerNumber],[DDATransMaster]![PromotionCode]) AS EmpJoin,
EmployeeLookup.ID AS EmpLookup,
FROM FROM DDATransMaster
LEFT JOIN EmployeeLookup ON NZ([DDATransMaster]![DirectSellerNumber],[DDATransMaster]![PromotionCode]) = EmployeeLookup.[Employee #])
You can create a query like this:
SELECT
IIf(EmpID Is Null, SomeCode, EmpID) AS join_field,
field2,
etc
FROM YourTable
Or if the query will always be used within an Access session, Nz is more concise.
SELECT
Nz(EmpID, SomeCode) AS join_field,
field2,
etc
FROM YourTable
When you join that query to your other table, the Access query designer can represent the join between join_field and some matching field in the other table. If you were to attempt the IIf or Nz as part of the join's ON clause, the query designer can't display the join correctly in Design View --- it could still work, but may not be as convenient if you're new to Access SQL.
See whether this SQL gives you what you want.
SELECT
dda.Fulfillment,
dda.ConfirmationNumber,
dda.PromotionCode,
dda.DirectSellerNumber,
NZ(dda.DirectSellerNumber,dda.PromotionCode) AS EmpJoin,
el.ID AS EmpLookup
FROM
DDATransMaster AS dda
LEFT JOIN EmployeeLookup AS el
ON NZ(dda.DirectSellerNumber,dda.PromotionCode) = el.[Employee #])
But I would use the Nz part in a subquery.
SELECT
sub.Fulfillment,
sub.ConfirmationNumber,
sub.PromotionCode,
sub.DirectSellerNumber,
sub.EmpJoin,
el.ID AS EmpLookup
FROM
(
SELECT
Fulfillment,
ConfirmationNumber,
PromotionCode,
DirectSellerNumber,
NZ(DirectSellerNumber,PromotionCode) AS EmpJoin
FROM DDATransMaster
) AS sub
LEFT JOIN EmployeeLookup AS el
ON sub.EmpJoin = el.[Employee #])
What about:
LEFT JOIN EmployeeListing ON NZ(EmpID, SomeCode)
as your join, nz() uses the second parameter if the first is null, I'm not 100% sure this sort of join works in access. Worth 20 seconds to try though.
Hope it works.
You Could use a Union:
SELECT DDATransMaster.Fulfillment,
DDATransMaster.ConfirmationNumber,
DDATransMaster.PromotionCode,
DDATransMaster.DirectSellerNumber,
EmployeeLookup.ID AS EmpLookup
FROM DDATransMaster
LEFT JOIN EmployeeLookup ON
DDATransMaster.DirectSellerNumber = EmployeeLookup.[Employee #]
where DDATransMaster.DirectSellerNumber IS NOT NULL
Union
SELECT DDATransMaster.Fulfillment,
DDATransMaster.ConfirmationNumber,
DDATransMaster.PromotionCode,
DDATransMaster.DirectSellerNumber,
EmployeeLookup.ID AS EmpLookup
FROM DDATransMaster
LEFT JOIN EmployeeLookup ON
DDATransMaster.PromotionCode = EmployeeLookup.[Employee #]
where DDATransMaster.DirectSellerNumber IS NULL;

Need help optimizing database query. Very unexperienced with indices

I need to optimize this query. The professor recommends using indices, but i'm very confused about how. If I could get just one example of what a good index is and why, and the actual code needed, I could definitely do the rest by myself. Any help would be awesome. (PSQL btw)
SELECT
x.enteredBy
, x.id
, count(DISTINCT xr.id)
, count(DISTINCT c.id)
, 'l'
FROM
((locationsV x left outer join locationReviews xr on x.id = xr.lid)
left outer join reviews r on r.id = xr.id)
left outer join comments c on xr.id = c.reviewId
WHERE
x.vNo = 0
AND (r.enteredBy IS NULL OR
(r.enteredBy <> x.enteredBy
AND c.enteredBy <> x.enteredBy
AND r.enteredBY NOT IN
(SELECT requested FROM friends WHERE requester = x.enteredBY)
AND r.enteredBY NOT IN
(SELECT requester FROM friends WHERE requested = x.enteredBY)))
AND (c.enteredBy IS NULL OR
(c.enteredBY NOT IN
(SELECT requested FROM friends WHERE requester = x.enteredBY)
AND c.enteredBY NOT IN
(SELECT requester FROM friends WHERE requested = x.enteredBY)))
GROUP BY
x.enteredBy
, x.id
I tried adding something like this to the beginning, but the overall time it took didn't change.
CREATE INDEX friends1_idx ON friends(requested);
CREATE INDEX friends2_idx ON friends(requester);
I think the SQL itself could be optimized to improve performance in addition to looking at indexes. Having those IN clauses in the WHERE clause may cause the optimizer do full table scans. So if you could move those to be tables in the FROM section you would have better performance. Also, having the COUNT(DISTINCT ...) clauses in in the SELECT statement seems problematic. You would likely be better off if you could make changes so the DISTINCT clauses were necessary there and simply use the COUNT aggregate function.
Consider using a SQL statement in the FROM clause before you do the left join--a structure something like this:
SELECT ...
FROM Table1 LEFT JOIN
(SELECT ... FROM Table2 INNER JOIN Table3 ON ...) AS Table4 ON
Table1.somecolumn = Table4.somecolumn
...
I know this isn't giving you the solution, but hopefully it will help you to think about other aspects of the problem and to explore other ways to address performance.

Converting from Oracle Join to Postgres Join

I have two select statements that I am trying to port from Oracle to Postgres:
1) (Note: this is a subselect part of a bigger select)
SELECT 'Y'
FROM CRAFT MA, CONFIG MAC, ARMS SM
WHERE MCI.MS_INVENTORY_NUMBER = SM.MS_INVENTORY_NUMBER (+)
AND MCI.AB_BASE_ID = MA.AB_BASE_ID_LAUNCH AND SM.ACT_AC_TYPE = MAC.ACT_AC_TYPE
AND SM.MAC_ID = MAC.MAC_ID AND MAC.ACT_AC_TYPE = MA.ACT_AC_TYPE
AND MAC.MAC_ID = MA.MAC_ID_PRI
2)
SELECT ASP.ASP_SPACE_NM,
SUM(MO.MO_TKR_TOTAL_OFF_SCHEDULED) AS "TOTAL_PLANNED"
FROM MISSION_OBJECTIVE MO, SPACE ASP
WHERE ASP.ASP_SPACE_NM = MO.ASP_SPACE_NM (+)
AND MO.MO_MSN_CLASS_NM = 'TOP'
GROUP BY ASP.ASP_SPACE_NM
The (+) syntax is confusing for me... I know it signifies a "join", but I am not familiar enough with SQL to understand what is equivalent to what.
SELECT 'Y'
FROM CRAFT MA
JOIN CONFIG MAC
ON MAC.ACT_AC_TYPE = MA.ACT_AC_TYPE
AND MAC.MAC_ID = MA.MAC_ID_PRI
AND MA.AB_BASE_ID_LAUNCH = MCI.AB_BASE_ID
LEFT JOIN
ARMS SM
ON SM.MS_INVENTORY_NUMBER = MCI.MS_INVENTORY_NUMBER
WHERE SM.ACT_AC_TYPE = MAC.ACT_AC_TYPE
AND SM.MAC_ID = MAC.MAC_ID AND
and
SELECT ASP.ASP_SPACE_NM,
SUM(MO.MO_TKR_TOTAL_OFF_SCHEDULED) AS "TOTAL_PLANNED"
FROM SPACE ASP
LEFT JOIN
MISSION_OBJECTIVE MO
ON MO.ASP_SPACE_NM = ASP.ASP_SPACE_NM
WHERE MO.MO_MSN_CLASS_NM = 'TOP'
GROUP BY
ASP.ASP_SPACE_NM
I left the LEFT JOIN as it was in the original query, but it's redundant here due to the WHERE condition.
You may replace it with an INNER JOIN or just drop the (+) part.
(+) was Oracle's way of expressing an outer join before "LEFT JOIN" (etc.) was added to standard SQL. Some Oracle practitioners did not immediately switch over to the standard syntax, even after it was added to the Oracle dialect of SQL.
The answer you have accepted says that you can replace "LEFT JOIN" with "INNER JOIN". I'm not convinced. But I'm confused by the reference to "MCI" in the first query.
The original programmer probably had a reason for using outer join instead of inner join. You might want to check and see whether that original reason was valid.

Resources