Reputation: 35
I am using a Microsoft Access 2010 database to import values from one table and append them to a summary table.
One of the issues I am having is finding the previous and next value from the select statement.
This would look as follows.
JOINT JOINT AHEAD JOINT BEHIND
100103 200203
200203 300303 100103
300303 200203
I would like to create this using a SQL code
Upvotes: 2
Views: 2094
Reputation: 97100
Be cautious when considering correlated subqueries. They can be very slow. And if you build a query which includes two correlated subqueries, you will magnify the problem.
If your source table contains a smallish number of rows (say a few dozen), the slowness may not be an issue. However, if the table includes a thousand rows you will most certainly notice it. And if your JOINT
field is not indexed, the performance could be painfully slow.
If you will be running your query from within an Access session, you can use domain functions (DMin
and DMax
) instead of correlated subqueries. Domain functions are often criticized as slow. However, in this situation they can be dramatically faster than correlated subqueries.
Correction: You don't need to run your query from within an Access session for it to be able to use the DMin()
and DMax()
functions. I attached a VBScript example which opens an ADO Recordset based on my qryDomainFunctions
. It works without error and correctly reports RecordCount: 1000
I created a table, joints
, with a long integer field joint
as primary key and added 1000 rows. Then I created these 2 queries:
qryCorrelatedSubqueries:
SELECT
a.joint,
(SELECT TOP 1 joint
FROM joints b
WHERE b.joint>a.joint
ORDER BY joint) AS Ahead,
(SELECT TOP 1 joint
FROM joints b
WHERE b.joint<a.joint
ORDER BY joint DESC) AS Behind
FROM joints AS a;
qryDomainFunctions:
SELECT
j.joint,
DMin("joint","joints","joint > " & [joint]) AS joint_ahead,
DMax("joint","joints","joint < " & [joint]) AS joint_behind
FROM joints AS j;
Here is a transcript from the Immediate window where I compared the speed of those 2 queries, using the QueryDuration
function below. That function returns duration in milliseconds.
? QueryDuration("qryDomainFunctions")
0
? QueryDuration("qryCorrelatedSubqueries")
889
Note that both those queries benefit from the index on the joints
field. When I dropped the index, compacted the db, and re-ran the tests I got these results:
? QueryDuration("qryDomainFunctions")
16
? QueryDuration("qryCorrelatedSubqueries")
4570
This is the module with the code I used. QueryDuration
is by no means the last word on performance measurement. However it's good enough to give us a rough idea of the relative speeds of those 2 queries.
Option Compare Database
Option Explicit
Private Declare Function apiGetTickCount Lib "kernel32" _
Alias "GetTickCount" () As Long
Public Function QueryDuration(ByVal pQueryName As String) As Long
Dim db As DAO.Database
Dim lngStart As Long
Dim lngDone As Long
Dim rs As DAO.Recordset
Set db = CurrentDb()
lngStart = apiGetTickCount() ' milliseconds '
Set rs = db.OpenRecordset(pQueryName, dbOpenSnapshot)
If Not rs.EOF Then
rs.MoveLast
End If
lngDone = apiGetTickCount()
rs.Close
Set rs = Nothing
Set db = Nothing
QueryDuration = lngDone - lngStart
End Function
DomainFunctionsQuery.vbs:
Option Explicit
Dim cn, rs
Set cn = CreateObject("ADODB.Connection")
cn.Open "Provider=Microsoft.Jet.OLEDB.4.0;" & _
"Data Source='database1.mdb'"
Set rs = CreateObject("ADODB.Recordset")
rs.CursorLocation = 3 ' adUseClient '
rs.Open "qryDomainFunctions", cn, 3 ' adOpenStatic = 3 '
WScript.Echo "RecordCount: " & rs.RecordCount
rs.Close
Set rs = Nothing
cn.Close
Set cn = Nothing
Upvotes: 1
Reputation: 91356
How about:
SELECT a.JOINT,
(SELECT TOP 1 Joint
FROM Joint b
WHERE b.JOINT>a.JOINT
ORDER BY Joint) AS Ahead,
(SELECT TOP 1 Joint
FROM Joint b
WHERE b.JOINT<a.JOINT
ORDER BY Joint DESC) AS Behind
FROM Joint AS a;
Upvotes: 1