Should I be using a pass through query? (1 Viewer)

gojets1721

Registered User.
Local time
Yesterday, 16:26
Joined
Jun 11, 2019
Messages
429
Please note: I'm very new to SQL so please bare with me. I apologize if this is a stupid question.

So my backend is in SQL and I'm using Access as my front end. When/If I utilize queries in Access, should I be using passthrough queries or just normal ones? I already have the SQL tables linked into access and every guide online about pass through implies that they should be used if the SQL tables aren't already linked into Access.

Suggestions? I'm aiming for the best performance possible so I was interested in knowing more about when/if to use pass through queries
 

Minty

AWF VIP
Local time
Today, 00:26
Joined
Jul 26, 2013
Messages
10,371
The ODBC drivers make a very good job of optimising your queries from Access.
This can fall down if you use any user-defined functions from access VBA as the SQL server doesn't understand them, and can't use them.
At that point, move the function to SQL and then use a pass-through query or possibly better still a view if you want an editable recordset for a form.

Pass-throughs are only really of benefit if you want to run a parameterised stored procedure or something similar.
 

gojets1721

Registered User.
Local time
Yesterday, 16:26
Joined
Jun 11, 2019
Messages
429
user-defined functions from access VBA
Could you provide an example?

In a nutshell, I really just want to filter down the data. It's a DB of customer complaints and so I wouldn't mind a query to filter down specifically to 'timeliness' related complaints, for instance. I'm unsure if that should be down through a pass through or just a regular ole access select query. I was concerned about reducing the performance of using an sql backend by foolishly utilizing the wrong query type
 

Minty

AWF VIP
Local time
Today, 00:26
Joined
Jul 26, 2013
Messages
10,371
Let's say you have written a simple function in Access to add three days to a date (Aircode below untested!)

Code:
Function fnAddThreeDays(dDate as Date)

       fnAddThreeDays = Dateadd("d",3,dDate)

End Function

Now you have a query like

Code:
SELECT MyInvoiceNumber, InvoiceDate, fnAddThreeDays(InvoiceDate) as DateIWantToBePaid
FROM tblMYInvoices

This won't work well with SQL backend, as it will have to pass the records to Access to use the function. SQL Server doesn't know anything about a user VBA function in Access. It's not a local SQL server function.

Does that help?
 

gojets1721

Registered User.
Local time
Yesterday, 16:26
Joined
Jun 11, 2019
Messages
429
Could you provide an example?

Let's say you have written a simple function in Access to add three days to a date (Aircode below untested!)

Code:
Function fnAddThreeDays(dDate as Date)

       fnAddThreeDays = Dateadd("d",3,dDate)

End Function

Now you have a query like

Code:
SELECT MyInvoiceNumber, InvoiceDate, fnAddThreeDays(InvoiceDate) as DateIWantToBePaid
FROM tblMYInvoices

This won't work well with SQL backend, as it will have to pass the records to Access to use the function. SQL Server doesn't know anything about a user VBA function in Access. It's not a local SQL server function.

Does that help?
Yes! That makes total sense.

If I wanted to utilize queries to isolate specific categories of entries, would you suggest a local query or a pass through query? Or does it depend?
 

Minty

AWF VIP
Local time
Today, 00:26
Joined
Jul 26, 2013
Messages
10,371
It depends on how often you will use them.
If they are going to be used all over the place within your app, then I would probably create them as views, and just link them (as if they were tables), but as I caveat, I'm more used to using Azure SQL where connection speed can make queries run a little slower.

Try both, remember pass-through query data can't be edited.
 

Galaxiom

Super Moderator
Staff member
Local time
Today, 09:26
Joined
Jan 20, 2009
Messages
12,851
Code:
SELECT MyInvoiceNumber, InvoiceDate, fnAddThreeDays(InvoiceDate) as DateIWantToBePaid
FROM tblMYInvoices

This won't work well with SQL backend, as it will have to pass the records to Access to use the function. SQL Server doesn't know anything about a user VBA function in Access. It's not a local SQL server function.
That case isn't quite so bad because the ODBC knows what records to send and the function is then applied to the results by Access. What really sucks is if you use a UDF in the WHERE clause because the only way the function can be applied and the records selected is by sending the whole table to Access.

Using the same trivial function as an example:
Code:
 SELECT blah
FROM table
WHERE fnAddThreeDays(datefield) < DATE()

It is also the case in a fully Access situation where a UDF is used in a WHERE. The function must be applied to every record and indexes won't be used.

Joining a server table to an Access table will perform badly too.
 

Pat Hartman

Super Moderator
Staff member
Local time
Yesterday, 19:26
Joined
Feb 19, 2002
Messages
43,257
The example of the UDF in the Select clause is not where you run into a problem. As long as Access can pass through the Where clause, you won't need pass-through queries for select queries.

The example Minty gave did not use criteria so it wasn't a fair example. Access would pass through all of the query except the UDF part. Then when SQL Server returned the results of the select clause, Access would run a second query to apply the UDF. This is of course slower than If Access could have done it in one shot but would be unlikely to slow down the query sufficiently such that you needed to convert it to a stored procedure. If the query has criteria, the ODBC driver passes through the criteria so if you are selecting ONE row from a million row table, SQL server is still doing the heavy lifting and only a single row would be returned and then Access would run another query to get the UDF value.

Where you run into a problem is if the UDF is in the Where or Having clause. In that case, Access has to send the query to the server WITHOUT the WHERE clause. That means it has to select all one million rows, bring them back, and then apply the UDF locally to select the ONE record. Therein lies the problem. If that is your situation and you have a large table, you need to create a stored procedure and than a pass-through query to run it so that you only get back the single row.

The point is -- Access and the ODBC drivers make every effort to "pass through" all queries to the server to obtain the benefit of the server severely limiting the rows that get returned to Access. YOU, need to understand when this might be a problem and then work around it. It doesn't mean that EVERY query needs to be written as a pass-through, just that some MIGHT. I've been using various RDBMS' for over 25 years with linked tables and Access querydefs. Some of my applications have millions of rows. As long as I never bind a form/report to a table or a query without criteria, I get to take advantage of SQL Server, DB2, Oracle, et al to retrieve the rows efficiently and return them quickly. I have had to resort to stored procedures occasionally for complex reports and I do use pass through queries if I am doing bulk deletes. Otherwise, 99.9% of everything else just uses linked tables, Access queries, and bound forms/reports because I understand what types of things in queries will cause a problem.

Linked tables and Access queries will always be slightly slower than pass through queries because at a minimum, you have the overhead of ODBC processing the query before sending it off to the server. Most of the time, you won't feel any particular slowness. Occasionally, if you have a query with multiple joins, you might want to create a view to optimize the joins. That may be sufficient to work out the slowness. That doesn't mean you need to give up linked tables or bound forms. Views, unless they aggregate data are updateable just the way tables are.
 

strive4peace

AWF VIP
Local time
Yesterday, 18:26
Joined
Apr 3, 2020
Messages
1,004
@templeowls, adding on ...

anytime you have data that doesn't need to be edited, like the RowSource for a combobox or data for a report, using Pass-Throughs is a good idea for better performance.

> new to SQL

do you mean SQL Server or SQL, the language that queries are stored in? If the latter (or both), it's good to learn the basics

basic SQL for Access

SELECT
fieldlist
FROM tablename
IN anotherdatabase.mdb
WHERE criteria
GROUP BY fieldlist
HAVING criteria for fields that are aggregated
ORDER BY fieldlist;

~~~~

Alternately and more specifically, here is an SQL statement for a pass-through query where the back-end is SQL Server Azure, which uses similar but not the same syntax.

About Coalesce:

it will be common to use the Coalesce function if data is in SQL Server, instead of using Nz in Access.

~~
SELECT Q.QuestionID
, Coalesce( Q.Question, Left( Q.QuestLong + '',100)) AS Q
, Q.SetID as Set_
, Q.QuestionID as ID
, COALESCE(
(SELECT Sum( R.RScore) as QTotal
FROM dbo.Reaction AS R
INNER JOIN dbo.QReact AS QR
ON R.ReactID = QR.ReactID
WHERE
QR.QuestionID = Q.QuestionID
)
,0) as qScore
, Coalesce( Q.Question, Left( Coalesce(Q.QuestLong,''),200)) AS Question_
FROM dbo.QUESTION Q
WHERE ( 1=1 )
ORDER BY Left( Coalesce( Q.Question, Q.QuestLong, ''),100 )

~~
Note:
using WHERE ( 1=1 ) for criteria makes it easier for VBA code to change the WHERE clause.

This query also calculates a sum, qScore, which can be quite fast if you do it at the source!

~~~~
When querying a linked table, you use the Access flavor of SQL (Structured Query Language).

When using a Pass-Through query, Access doesn't care about any linked tables. The ODBC (Open DataBase Connectivity), which is a program(s) to translate from Access to native SQL to get the desired data, is bypassed so executing what is wanted is faster, and only what is needed is brought down.

> When/If I utilize queries in Access, should I be using passthrough queries or just normal ones?

That depends on the purpose of them. If you need to edit data, prehaps best to use queries based on linked tables, and limit the records with criteria for faster performance.

~~~ Pass-Thru
It's a good idea to keep saved queries for pass-throughs (perhaps named in a way that users don't see). Then, before opening an object, change the SQL for its data based on saved pass-through query (ies).

Pass-Through Queries define other properties than SQL such as the connect string. While you can set the other properties yourself, it can be convenient to include "_PT" in the query name to know that query is already set up to be a pass-through, and modify it's SQL for that user. Of course, each user should have thier own front-end.

To store values, like for criteria, database properties are handy. Here is some VBA code to handle object properties such as for the database.

VBA > Properties > Get and set ... read, write, show, delete
http://msaccessgurus.com/VBA/Code/Properties.htm

~~~ performance

> best performance possible

It took a long week to create an Access app to track questions and answers -- then more than a month to make it fast enough to run using an Azure back-end ... along with more changes, so not all of that additional time was performance.

Access is a great prototyping tool to figure out how to organize and present the information. It is also fast! So you don't have to worry about things like limiting the number of records you pull down.

However, once you've used Access to jump you to the next step, expect more time (and studying/learning ) to optimize everything ~
 
Last edited:

Galaxiom

Super Moderator
Staff member
Local time
Today, 09:26
Joined
Jan 20, 2009
Messages
12,851
anytime you have data that doesn't need to be edited, like the RowSource for a combobox or data for a report, using Pass-Throughs is a good idea for better performance.
Do you have some performance stats on that? The ODBC would automatically pass through a trivial query like that and the query plan would be stored by the server.
 

strive4peace

AWF VIP
Local time
Yesterday, 18:26
Joined
Apr 3, 2020
Messages
1,004
@Galaxiom, you're right, I should never say always -- with the big data anyway. However, I generally convert most all of them (that are read-only) just to shave off every possible nanosecond ;)
 
Last edited:

isladogs

MVP / VIP
Local time
Today, 00:26
Joined
Jan 14, 2017
Messages
18,212
.....
Views, unless they aggregate data are updateable just the way tables are.

@Pat Hartman
I agree with all the points in your post except for the final sentence
Views that are updateable in SQL Server will be read only in Access unless a primary key field is applied to the linked view
 

Pat Hartman

Super Moderator
Staff member
Local time
Yesterday, 19:26
Joined
Feb 19, 2002
Messages
43,257
Thanks Colin. My views seem to be updateable without having to do that although I do remember in the early days having to run a DDL query in Access to define the unique index. Also, the query needed to be rerun if you relinked the tables either do to a schema change in the BE or because you were swapping BE's. Most of my SQL server apps have at least three BE versions - test -- acceptance -- production. Test was for me or anyone else doing unit testing. The users doing final testing used the middle version. When they were happy, the rollout went to the production BE. At Sikorsky, I had EIGHT steps to move to final production:)

I'll see if I can figure it out.
 

isladogs

MVP / VIP
Local time
Today, 00:26
Joined
Jan 14, 2017
Messages
18,212
IIRC, using the ODBC wizard, you can choose to define a PK field to the view as the final step.
As I always use DSN-less approach, I never use the wizard. Where I need to update the view I add an index using code originally by Juan Soto.
In fact I wrote a short article about this a couple of years ago
 
Last edited:

Pat Hartman

Super Moderator
Staff member
Local time
Yesterday, 19:26
Joined
Feb 19, 2002
Messages
43,257
You also have to reset your passthrough queries when you relink BE's. I use the code below plus I just keep a bunch of DDL queries that I run to reset the PKs on views. This was the only app I ever had to do this for though.

Code:
' relink pass-through queries
    For Each qdef In db.QueryDefs
        If InStr(qdef.Connect, DatabaseName) Then
            qdef.Connect = constr
            QueryCount = QueryCount + 1
        End If
    Next
 

Users who are viewing this thread

Top Bottom