Interpolation Query...

  • Thread starter Thread starter DIOS
  • Start date Start date
D

DIOS

I have a table that looks like so:
fldAlt fldTemp
250 20
270 10
290 5

What i want to do is send a query such that if the fldAlt is not found
then I get a value for fldTemp back that is interpolated on the value
above and below it. Is this possible or do I have to figure out the lower
and upper value
outside of the query and then get two records and then do the
interpolation? Any suggestions are welcome.

AGP
 
Your data sample suggests non-linear interpolation.

I think it is possible to create a query with a linear factor for every
record that has a higher fldAlt later in the table. But I think you are
better of with a function that does some lookup, and calculates the
intermediate value.

To get the next higher fldAlt/fldTemp, when supplied a parAlt: (AIR CODE)

select top 1 fldAlt, fldTemp from yourTable where fldAlt>[parAlt] order
by fldAlt;

to get the previous lower fldAlt/fldTemp:

select top 1 fldAlt, fldTemp from yourTable where fldAlt<[parAlt] order
by fldAlt DESC;
 
Hi,


You can only interpolate (between the min and max Temp value) with the
following:


SELECT a.Alt+ (x-a.Temp)*(b.Alt-a.Alt)/(b.Temp-a.Temp)
FROM ( MyData As a
INNER JOIN MyData As b ON b.Temp> a.Temp )
INNER JOIN MyData As c ON c.Temp> a.Temp

WHERE a.Temp<=x AND b.Temp>x
GROUP BY a.temp, a.Alt, b.temp, b.Alt
HAVING b.Temp = MIN(c.Temp)




where x is the parameter, the Temp value you are looking for the Alt
(interpolated) result. It works for an arbitrary number of records, as long
as you don't have duplicated Temp value, and the interpolation is linear.

Hoping it may help,
Vanderghast, Access MVP
 
Assuming your table is called tblAltTemp (or substitute in the code below
accordingly), put the following code in a general module:

Function calc_alt_temp(alt As Double) As Double
Dim db As DAO.Database
Dim rst As DAO.Recordset
strSQL = "SELECT * FROM tblAltTemp ORDER BY fldAlt"
Set db = CurrentDb()
Set rst = db.OpenRecordset(strSQL)
rst.MoveFirst
lalt = rst.Fields("fldAlt")
ltmp = rst.Fields("fldTemp")
rst.MoveNext

If alt < lalt Then
MsgBox "Altitude below table range"
GoTo f_exit
End If
Do Until rst.EOF
ualt = rst.Fields("fldAlt")
utmp = rst.Fields("fldTemp")
If alt <= ualt Then
calc_alt_temp = ltmp + (utmp - ltmp) * (alt - lalt) / (ualt - lalt)
Exit Function
End If
lalt = rst.Fields("fldAlt")
ltmp = rst.Fields("fldTemp")
rst.MoveNext
Loop
If alt > ltmp Then
MsgBox "Altitude above table range"
GoTo f_exit
End If

f_exit:
rst.Close
End Function

This done, you can use =calc_alt_temp(altitude) anywhere in your database
(queries, forms, reports, code...) to return the temperature for altitude
(put the altitude number, or an expression for it, as the fucntion argument
in the brackets). It works just like any Access built-in function.

Note: for the code to work, you will need to add the Microsoft DAO Object
Library, if not there already. To do this, while in the VBA window, go Tools
References and select it (DAO 3.51 for Access 97, DAO 3.6 for Access 2000
or later).

HTH,
Nikos
 
Thanks for all the help. the data was just randon numbers I threw in
to illustarte my point. In actuality i would like to stick with linear
interpolation. However, my problem has become more complex where now I
have to do two-dimensional interpolation. My table now consists of the
following structure:

fldReg fldLat fldAlt fldTemp
ENA 35 430 4.5
ENA 35 410 3.2
ENA 35 390 1.8
ENA 31 430 3.5
ENA 31 410 2.9
ENA 31 390 1.7

For any given Lat and Alt i want to come into the table and do a 2D
interpolation. For a lat of 32.5 and Alt of 420 I tried an inititial
query to get me the "ceiling" records. I just cant seem to get a grasp
on how I can get both the celing and floor in one shot.
SELECT * FROM tblData
WHERE fldReg='ENA' AND fldLat<=32.5
AND fldAlt<=420

The interpolation would end up looking like so:

LAT
31 32.5 35
Alt 430 3.5 4.5
420 x
410 2.9 3.2

So in actuality I need 4 records to do the full interpolation. I can
do the calculation outside of the query I just cant seem to build my
query for this type of problem.

AGP
 
Hi,

I changed the fields name to be more general: Site, x, y, and u and called
the table xyData.


xyData
Site x y u
ena 35 430 4.5
ena 35 410 3.2
ena 35 390 1.8
ena 31 430 3.5
ena 31 410 2.9
ena 31 390 1.7





A possible SQL statement then look like:
=====================================
SELECT 0.25*((1-[xi])*(1-[eta])*[a].
+(1+[xi])*(1-[eta])*.
+(1+[xi])*(1+[eta])*[c].
+(1-[xi])*(1+[eta])*[d].) AS uw,
a.Site,
2*([xw]-[a].[x])/(.[x]-[a].[x])-1 AS xi,
2*([yw]-[a].[y])/([d].[y]-[a].[y])-1 AS eta

FROM ((((((xyData AS a INNER JOIN xyData AS b
ON (a.y = b.y) AND (a.Site = b.Site))
INNER JOIN xyData AS d
ON (a.x = d.x) AND (a.Site = d.Site))
INNER JOIN xyData AS c
ON (d.y = c.y) AND (b.x = c.x) AND (a.Site = c.Site))
INNER JOIN xyData AS xmin
ON a.Site = xmin.Site)
INNER JOIN xyData AS ymin
ON a.Site = ymin.Site)
INNER JOIN xyData AS xmax
ON a.Site = xmax.Site)
INNER JOIN xyData AS ymax
ON a.Site = ymax.Site

WHERE (((a.x)<.[x])
AND ((a.y)<[d].[y])
AND ((xmin.x)<=[xw])
AND ((ymin.y)<=[yw])
AND ((xmax.x)>[xw])
AND ((ymax.y)>[yw]))

GROUP BY a.Site, a.x, a.y, a.u, b.x, b.y, b.u, c.x, c.y, c.u, d.x, d.y, d.u

HAVING (((2*([xw]-[a].[x])/(.[x]-[a].[x])-1) Between -1 And 1)
AND ((2*([yw]-[a].[y])/([d].[y]-[a].[y])-1) Between -1 And 1)
AND ((a.x)=Max([xmin].[x]))
AND ((a.y)=Max([ymin].[y]))
AND ((c.x)=Min([xmax].[x]))
AND ((c.y)=Min([ymax].[y])));
==========================================


If you run the query, you would be ask for xw ( x-wanted) and for yw (
y-wanted). I supplied, as example, 33 and 420, respectively, and got:


uw Site xi eta
3.525 ena 0 0




uw, the interpollated result, is thus 3.525. xi and eta are just
intermediate result (they should be selected else Jet barks). Note that the
query does NOT work in MS SQL Server ( because MS SQL Server does more, as
usual, ... here, it does more than just barking, it does not allow to build
an expression upon alias at all).


Some limitations: You cannot extrapollate. The data has to be "tabular" (
by opposition to be a "cloud" of points). The x and y data type should
preferably be Decimal rather than Float.



How it works? There is the math and there is the SQL expression of the math.

Mathematically, it is quite easy, in fact, once we get the "method". First,
since the data is tabular, we can assume we interpollate between four
points, a, b, c and d, like here below:


^ eta
d | c
o------|------o
| | |
| | |
---+------+------+----> xi
| | |
| | |
o-------|------o
a b



where xi and eta axis are somehow, axis telling us "where we are", at what
intermediate point we want the interpollation. That simplifies greatly the
equations if we assume that xi varies from -1 to +1 ( ie, points a and d
are at xi = -1 ) and eta too, from -1 to +1 ( so point c is at xi=1,
eta=1 ). As example, point xi=0, eta=0 implies we are exactly at the
centroid of the four points.


So, knowing where we are, at a point (xi, eta), the u value is then
interpollated with the Lagrangian formula in 2 dimensions (after
simplications from our case algebrically included):

u = ( 1/4 ) * ( (1-xi)(1-eta) Ua
+ (1+xi)(1-eta) Ub
+ (1+xi)(1+eta) Uc
+ (1-xi)(1+eta) Ud )



with Ua, Ub, Uc and Ud the value of the function at points a, b, c and d
(ie, the value we read from the table).


Since we know how to do it mathematically, how can we do it with SQL? quite
easy. I bring a reference to the table eight times, but four of those are
aliased as a, b, c and d. Indeed, those are the four "points", nothing more.
I also use inner join between those references to position them among
themseves: ON a.x = d.x, as example, means I wish a and d be two points on
the same vertical ( having the same x value). I also use conditions like
a.x < b.x to specify that I wish point a to be at the left of point b.
Having my four tables (points) properly positionned, knowing xw and yw, I
can compute xi, eta, and u-wanted.

Now, since we have more than four points in the table, we have to limit the
result to the one that uniquely position our point "a" in the whole table.
That is the role of the four other references of the table. Let us position
point a uniquely in the table, that is the role of xmin and ymin. Limiting
xmin.x values to be <= xw, the x where we want the interpolation, means that
xmin reference would refer to only the points, in the table, at the left of
xw. We just then need to impose a.x to be that maximum of those xmin.x to
get the unique a.x value that is the characteristic of the point a. I do the
same about the y direction, implying ymin.y, yw, and finally, a.y. Since SQL
does not know the data is a table, we also have to repeat the job to
position exactly the point c, as being the first up and right of the point
(xw, yw). We do it exactly as we did it for imposing point a to bhe the
first left and down of (xw, yw).


That's all.


To convert that SQL statement into MS SQL Server, because that statement
works in Jet but not in MS SQL Server, a possible solution is to replace xi
by 2*([xw]-[a].[x])/(.[x]-[a].[x])-1 everywhere, and do something
similar for eta, that is not to simplify the "look" of the statement,
neither nothing to give it a friendly smile, but those are limitations of
syntax... the overall process is still ... elementary...


Hoping it may help,
Vanderghast, Access MVP
 
WOW!!! Thanx for all the information and data. Couple things...the
fact that it does not extrapolate is OK as I dont want any data
outside of my tables. Also, from looking at the query...if I have the
same type of data but also for many different regions...then I can
alter the query to only look at the data for a certain region by
modifying the WHERE clause to:
WHERE (((a.x)<.[x])
AND ((a.y)<[d].[y])
AND ((xmin.x)<=[xw])
AND ((ymin.y)<=[yw])
AND ((xmax.x)>[xw])
AND ((ymax.y)>[yw]))

AND a.Site='myRegion'

Going into my query I will know (if I use your notation) my site, my
x, and my y. I can then generate a query on the fly and then read the
field u from the returned recordset to get my interpolated value. I
would check for a returned recordset and if none then I would theorize
that one of my variables was out of the tables range.

I will test and post my results.

AGP




Michel Walsh said:
Hi,

I changed the fields name to be more general: Site, x, y, and u and called
the table xyData.


xyData
Site x y u
ena 35 430 4.5
ena 35 410 3.2
ena 35 390 1.8
ena 31 430 3.5
ena 31 410 2.9
ena 31 390 1.7





A possible SQL statement then look like:
=====================================
SELECT 0.25*((1-[xi])*(1-[eta])*[a].
+(1+[xi])*(1-[eta])*.
+(1+[xi])*(1+[eta])*[c].
+(1-[xi])*(1+[eta])*[d].) AS uw,
a.Site,
2*([xw]-[a].[x])/(.[x]-[a].[x])-1 AS xi,
2*([yw]-[a].[y])/([d].[y]-[a].[y])-1 AS eta

FROM ((((((xyData AS a INNER JOIN xyData AS b
ON (a.y = b.y) AND (a.Site = b.Site))
INNER JOIN xyData AS d
ON (a.x = d.x) AND (a.Site = d.Site))
INNER JOIN xyData AS c
ON (d.y = c.y) AND (b.x = c.x) AND (a.Site = c.Site))
INNER JOIN xyData AS xmin
ON a.Site = xmin.Site)
INNER JOIN xyData AS ymin
ON a.Site = ymin.Site)
INNER JOIN xyData AS xmax
ON a.Site = xmax.Site)
INNER JOIN xyData AS ymax
ON a.Site = ymax.Site

WHERE (((a.x)<.[x])
AND ((a.y)<[d].[y])
AND ((xmin.x)<=[xw])
AND ((ymin.y)<=[yw])
AND ((xmax.x)>[xw])
AND ((ymax.y)>[yw]))

GROUP BY a.Site, a.x, a.y, a.u, b.x, b.y, b.u, c.x, c.y, c.u, d.x, d.y, d.u

HAVING (((2*([xw]-[a].[x])/(.[x]-[a].[x])-1) Between -1 And 1)
AND ((2*([yw]-[a].[y])/([d].[y]-[a].[y])-1) Between -1 And 1)
AND ((a.x)=Max([xmin].[x]))
AND ((a.y)=Max([ymin].[y]))
AND ((c.x)=Min([xmax].[x]))
AND ((c.y)=Min([ymax].[y])));
==========================================


If you run the query, you would be ask for xw ( x-wanted) and for yw (
y-wanted). I supplied, as example, 33 and 420, respectively, and got:


uw Site xi eta
3.525 ena 0 0




uw, the interpollated result, is thus 3.525. xi and eta are just
intermediate result (they should be selected else Jet barks). Note that the
query does NOT work in MS SQL Server ( because MS SQL Server does more, as
usual, ... here, it does more than just barking, it does not allow to build
an expression upon alias at all).


Some limitations: You cannot extrapollate. The data has to be "tabular" (
by opposition to be a "cloud" of points). The x and y data type should
preferably be Decimal rather than Float.



How it works? There is the math and there is the SQL expression of the math.

Mathematically, it is quite easy, in fact, once we get the "method". First,
since the data is tabular, we can assume we interpollate between four
points, a, b, c and d, like here below:


^ eta
d | c
o------|------o
| | |
| | |
---+------+------+----> xi
| | |
| | |
o-------|------o
a b



where xi and eta axis are somehow, axis telling us "where we are", at what
intermediate point we want the interpollation. That simplifies greatly the
equations if we assume that xi varies from -1 to +1 ( ie, points a and d
are at xi = -1 ) and eta too, from -1 to +1 ( so point c is at xi=1,
eta=1 ). As example, point xi=0, eta=0 implies we are exactly at the
centroid of the four points.


So, knowing where we are, at a point (xi, eta), the u value is then
interpollated with the Lagrangian formula in 2 dimensions (after
simplications from our case algebrically included):

u = ( 1/4 ) * ( (1-xi)(1-eta) Ua
+ (1+xi)(1-eta) Ub
+ (1+xi)(1+eta) Uc
+ (1-xi)(1+eta) Ud )



with Ua, Ub, Uc and Ud the value of the function at points a, b, c and d
(ie, the value we read from the table).


Since we know how to do it mathematically, how can we do it with SQL? quite
easy. I bring a reference to the table eight times, but four of those are
aliased as a, b, c and d. Indeed, those are the four "points", nothing more.
I also use inner join between those references to position them among
themseves: ON a.x = d.x, as example, means I wish a and d be two points on
the same vertical ( having the same x value). I also use conditions like
a.x < b.x to specify that I wish point a to be at the left of point b.
Having my four tables (points) properly positionned, knowing xw and yw, I
can compute xi, eta, and u-wanted.

Now, since we have more than four points in the table, we have to limit the
result to the one that uniquely position our point "a" in the whole table.
That is the role of the four other references of the table. Let us position
point a uniquely in the table, that is the role of xmin and ymin. Limiting
xmin.x values to be <= xw, the x where we want the interpolation, means that
xmin reference would refer to only the points, in the table, at the left of
xw. We just then need to impose a.x to be that maximum of those xmin.x to
get the unique a.x value that is the characteristic of the point a. I do the
same about the y direction, implying ymin.y, yw, and finally, a.y. Since SQL
does not know the data is a table, we also have to repeat the job to
position exactly the point c, as being the first up and right of the point
(xw, yw). We do it exactly as we did it for imposing point a to bhe the
first left and down of (xw, yw).


That's all.


To convert that SQL statement into MS SQL Server, because that statement
works in Jet but not in MS SQL Server, a possible solution is to replace xi
by 2*([xw]-[a].[x])/(.[x]-[a].[x])-1 everywhere, and do something
similar for eta, that is not to simplify the "look" of the statement,
neither nothing to give it a friendly smile, but those are limitations of
syntax... the overall process is still ... elementary...


Hoping it may help,
Vanderghast, Access MVP


DIOS said:
Thanks for all the help. the data was just randon numbers I threw in
to illustarte my point. In actuality i would like to stick with linear
interpolation. However, my problem has become more complex where now I
have to do two-dimensional interpolation. My table now consists of the
following structure:

fldReg fldLat fldAlt fldTemp
ENA 35 430 4.5
ENA 35 410 3.2
ENA 35 390 1.8
ENA 31 430 3.5
ENA 31 410 2.9
ENA 31 390 1.7

For any given Lat and Alt i want to come into the table and do a 2D
interpolation. For a lat of 32.5 and Alt of 420 I tried an inititial
query to get me the "ceiling" records. I just cant seem to get a grasp
on how I can get both the celing and floor in one shot.
SELECT * FROM tblData
WHERE fldReg='ENA' AND fldLat<=32.5
AND fldAlt<=420

The interpolation would end up looking like so:

LAT
31 32.5 35
Alt 430 3.5 4.5
420 x
410 2.9 3.2

So in actuality I need 4 records to do the full interpolation. I can
do the calculation outside of the query I just cant seem to build my
query for this type of problem.

AGP
 
OK...i tried it and it works pretty well but there is one big
drawback. For a table like the one above the query generates a
recordset in a second or so. Now my actual table is composed of 300+
records which can grow to a few thousand. When I run the query on that
table it takes forever to return a recordset. On one test...its been
15 minutes and no recordset yet. Looks like Im going to have to try a
different approach.

AGP

Michel Walsh said:
Hi,

I changed the fields name to be more general: Site, x, y, and u and called
the table xyData.


xyData
Site x y u
ena 35 430 4.5
ena 35 410 3.2
ena 35 390 1.8
ena 31 430 3.5
ena 31 410 2.9
ena 31 390 1.7





A possible SQL statement then look like:
=====================================
SELECT 0.25*((1-[xi])*(1-[eta])*[a].
+(1+[xi])*(1-[eta])*.
+(1+[xi])*(1+[eta])*[c].
+(1-[xi])*(1+[eta])*[d].) AS uw,
a.Site,
2*([xw]-[a].[x])/(.[x]-[a].[x])-1 AS xi,
2*([yw]-[a].[y])/([d].[y]-[a].[y])-1 AS eta

FROM ((((((xyData AS a INNER JOIN xyData AS b
ON (a.y = b.y) AND (a.Site = b.Site))
INNER JOIN xyData AS d
ON (a.x = d.x) AND (a.Site = d.Site))
INNER JOIN xyData AS c
ON (d.y = c.y) AND (b.x = c.x) AND (a.Site = c.Site))
INNER JOIN xyData AS xmin
ON a.Site = xmin.Site)
INNER JOIN xyData AS ymin
ON a.Site = ymin.Site)
INNER JOIN xyData AS xmax
ON a.Site = xmax.Site)
INNER JOIN xyData AS ymax
ON a.Site = ymax.Site

WHERE (((a.x)<.[x])
AND ((a.y)<[d].[y])
AND ((xmin.x)<=[xw])
AND ((ymin.y)<=[yw])
AND ((xmax.x)>[xw])
AND ((ymax.y)>[yw]))

GROUP BY a.Site, a.x, a.y, a.u, b.x, b.y, b.u, c.x, c.y, c.u, d.x, d.y, d.u

HAVING (((2*([xw]-[a].[x])/(.[x]-[a].[x])-1) Between -1 And 1)
AND ((2*([yw]-[a].[y])/([d].[y]-[a].[y])-1) Between -1 And 1)
AND ((a.x)=Max([xmin].[x]))
AND ((a.y)=Max([ymin].[y]))
AND ((c.x)=Min([xmax].[x]))
AND ((c.y)=Min([ymax].[y])));
==========================================


If you run the query, you would be ask for xw ( x-wanted) and for yw (
y-wanted). I supplied, as example, 33 and 420, respectively, and got:


uw Site xi eta
3.525 ena 0 0




uw, the interpollated result, is thus 3.525. xi and eta are just
intermediate result (they should be selected else Jet barks). Note that the
query does NOT work in MS SQL Server ( because MS SQL Server does more, as
usual, ... here, it does more than just barking, it does not allow to build
an expression upon alias at all).


Some limitations: You cannot extrapollate. The data has to be "tabular" (
by opposition to be a "cloud" of points). The x and y data type should
preferably be Decimal rather than Float.



How it works? There is the math and there is the SQL expression of the math.

Mathematically, it is quite easy, in fact, once we get the "method". First,
since the data is tabular, we can assume we interpollate between four
points, a, b, c and d, like here below:


^ eta
d | c
o------|------o
| | |
| | |
---+------+------+----> xi
| | |
| | |
o-------|------o
a b



where xi and eta axis are somehow, axis telling us "where we are", at what
intermediate point we want the interpollation. That simplifies greatly the
equations if we assume that xi varies from -1 to +1 ( ie, points a and d
are at xi = -1 ) and eta too, from -1 to +1 ( so point c is at xi=1,
eta=1 ). As example, point xi=0, eta=0 implies we are exactly at the
centroid of the four points.


So, knowing where we are, at a point (xi, eta), the u value is then
interpollated with the Lagrangian formula in 2 dimensions (after
simplications from our case algebrically included):

u = ( 1/4 ) * ( (1-xi)(1-eta) Ua
+ (1+xi)(1-eta) Ub
+ (1+xi)(1+eta) Uc
+ (1-xi)(1+eta) Ud )



with Ua, Ub, Uc and Ud the value of the function at points a, b, c and d
(ie, the value we read from the table).


Since we know how to do it mathematically, how can we do it with SQL? quite
easy. I bring a reference to the table eight times, but four of those are
aliased as a, b, c and d. Indeed, those are the four "points", nothing more.
I also use inner join between those references to position them among
themseves: ON a.x = d.x, as example, means I wish a and d be two points on
the same vertical ( having the same x value). I also use conditions like
a.x < b.x to specify that I wish point a to be at the left of point b.
Having my four tables (points) properly positionned, knowing xw and yw, I
can compute xi, eta, and u-wanted.

Now, since we have more than four points in the table, we have to limit the
result to the one that uniquely position our point "a" in the whole table.
That is the role of the four other references of the table. Let us position
point a uniquely in the table, that is the role of xmin and ymin. Limiting
xmin.x values to be <= xw, the x where we want the interpolation, means that
xmin reference would refer to only the points, in the table, at the left of
xw. We just then need to impose a.x to be that maximum of those xmin.x to
get the unique a.x value that is the characteristic of the point a. I do the
same about the y direction, implying ymin.y, yw, and finally, a.y. Since SQL
does not know the data is a table, we also have to repeat the job to
position exactly the point c, as being the first up and right of the point
(xw, yw). We do it exactly as we did it for imposing point a to bhe the
first left and down of (xw, yw).


That's all.


To convert that SQL statement into MS SQL Server, because that statement
works in Jet but not in MS SQL Server, a possible solution is to replace xi
by 2*([xw]-[a].[x])/(.[x]-[a].[x])-1 everywhere, and do something
similar for eta, that is not to simplify the "look" of the statement,
neither nothing to give it a friendly smile, but those are limitations of
syntax... the overall process is still ... elementary...


Hoping it may help,
Vanderghast, Access MVP


DIOS said:
Thanks for all the help. the data was just randon numbers I threw in
to illustarte my point. In actuality i would like to stick with linear
interpolation. However, my problem has become more complex where now I
have to do two-dimensional interpolation. My table now consists of the
following structure:

fldReg fldLat fldAlt fldTemp
ENA 35 430 4.5
ENA 35 410 3.2
ENA 35 390 1.8
ENA 31 430 3.5
ENA 31 410 2.9
ENA 31 390 1.7

For any given Lat and Alt i want to come into the table and do a 2D
interpolation. For a lat of 32.5 and Alt of 420 I tried an inititial
query to get me the "ceiling" records. I just cant seem to get a grasp
on how I can get both the celing and floor in one shot.
SELECT * FROM tblData
WHERE fldReg='ENA' AND fldLat<=32.5
AND fldAlt<=420

The interpolation would end up looking like so:

LAT
31 32.5 35
Alt 430 3.5 4.5
420 x
410 2.9 3.2

So in actuality I need 4 records to do the full interpolation. I can
do the calculation outside of the query I just cant seem to build my
query for this type of problem.

AGP
 
Hi,


The following should be faster ( at execution time ), but we need 5 queries.



The fifth and final query, the one you call (and it would call the four
other automatically) is:

====================================
SELECT 0.25*((1-[xi])*(1-[eta])*a.u
+(1+[xi])*(1-[eta])*b.u
+(1+[xi])*(1+[eta])*c.u
+(1-[xi])*(1+[eta])*d.u) AS uw,

2*([xw]-a.x)/(b.x-a.x)-1 AS xi,
2*([yw]-a.y)/(d.y-a.y)-1 AS eta

FROM ( SELECT x, y, u
FROM xyData
WHERE x IN( SELECT * FROM Qxmin )
AND y IN ( SELECT * FROM Qymin) ) As a,

( SELECT x, y, u
FROM xyData
WHERE x IN( SELECT * FROM Qxmax )
AND y IN ( SELECT * FROM Qymin) ) As b,

( SELECT x, y, u
FROM xyData
WHERE x IN( SELECT * FROM Qxmax )
AND y IN ( SELECT * FROM Qymax) ) As c,

( SELECT x, y, u
FROM xyData
WHERE x IN( SELECT * FROM Qxmin )
AND y IN ( SELECT * FROM Qymax) ) As d
==================================



The four other query, Qxmin, Qxmax, Qymin and Qymax are the ones we call in
the WHERE statements. Here their code:


=Qxmax==========
SELECT a.x
FROM xyData AS a INNER JOIN xyData AS amax ON a.Site=amax.Site
WHERE a.x>xw And amax.x>xw
GROUP BY a.x
HAVING a.x=MIN(amax.x);
=================

=Qxmin===========
SELECT a.x
FROM xyData AS a INNER JOIN xyData AS amin ON a.Site=amin.Site
WHERE a.x<=xw And amin.x<=xw
GROUP BY a.x
HAVING a.x=MAX(amin.x);
==================

=Qymin============
SELECT a.y
FROM xyData AS a INNER JOIN xyData AS amin ON a.Site=amin.Site
WHERE a.y<=yw And amin.y<=yw
GROUP BY a.y
HAVING a.y=MAX(amin.y);
==================

and

=Qymax===========
SELECT a.y
FROM xyData AS a INNER JOIN xyData AS amax ON a.Site=amax.Site
WHERE a.y>yw And amax.y>yw
GROUP BY a.y
HAVING a.y=MIN(amax.y);
==================

they just supply the x and y values in the table that "surround" the point
(xw, yw) . The joins are much simpler and the optimizer should be able to
recognize the repetitivity of the expressions to evaluate them just once...
making the run time solution much better. You can add a condition on the
Site value in the WHERE clause of the four auxiliary queries.


The math is the same, I just re-arranged the SQL.




Hoping it runs faster,
Vanderghast, Access MVP
 
Ok I tried this approach but when I enter all queries in my Access
database as 5 seperate queries, the main query does not run saying the
table is not found. So I just did a substitution in the main query
with all the smaller queries and it works although now I get a 4
records returned and Im not sure what the returned data is supposed to
give me. I get uw, xi, and eta.

AGP
 
Hi,


"the" table is not found? Have you tried to edit the SQL statement from
the DESIGN VIEW? If so, there is a "feature" in Access that changes the SQL
code when it SHOULD not, mainly, adding a " [ ]dot " syntax here and there.
If so, try to remove the [ ] and the dot after the ] , replace them with the
original ( ), and that should do the trick... and do not edit the code
through the designer Design-view, for that query.


Hoping it may help,
Vanderghast, Access MVP


DIOS said:
Ok I tried this approach but when I enter all queries in my Access
database as 5 seperate queries, the main query does not run saying the
table is not found. So I just did a substitution in the main query
with all the smaller queries and it works although now I get a 4
records returned and Im not sure what the returned data is supposed to
give me. I get uw, xi, and eta.

AGP

"Michel Walsh" <vanderghast@VirusAreFunnierThanSpam> wrote in message
Hi,


The following should be faster ( at execution time ), but we need 5 queries.



The fifth and final query, the one you call (and it would call the four
other automatically) is:

====================================
SELECT 0.25*((1-[xi])*(1-[eta])*a.u
+(1+[xi])*(1-[eta])*b.u
+(1+[xi])*(1+[eta])*c.u
+(1-[xi])*(1+[eta])*d.u) AS uw,

2*([xw]-a.x)/(b.x-a.x)-1 AS xi,
2*([yw]-a.y)/(d.y-a.y)-1 AS eta

FROM ( SELECT x, y, u
FROM xyData
WHERE x IN( SELECT * FROM Qxmin )
AND y IN ( SELECT * FROM Qymin) ) As a,

( SELECT x, y, u
FROM xyData
WHERE x IN( SELECT * FROM Qxmax )
AND y IN ( SELECT * FROM Qymin) ) As b,

( SELECT x, y, u
FROM xyData
WHERE x IN( SELECT * FROM Qxmax )
AND y IN ( SELECT * FROM Qymax) ) As c,

( SELECT x, y, u
FROM xyData
WHERE x IN( SELECT * FROM Qxmin )
AND y IN ( SELECT * FROM Qymax) ) As d
==================================



The four other query, Qxmin, Qxmax, Qymin and Qymax are the ones we call in
the WHERE statements. Here their code:


=Qxmax==========
SELECT a.x
FROM xyData AS a INNER JOIN xyData AS amax ON a.Site=amax.Site
WHERE a.x>xw And amax.x>xw
GROUP BY a.x
HAVING a.x=MIN(amax.x);
=================

=Qxmin===========
SELECT a.x
FROM xyData AS a INNER JOIN xyData AS amin ON a.Site=amin.Site
WHERE a.x<=xw And amin.x<=xw
GROUP BY a.x
HAVING a.x=MAX(amin.x);
==================

=Qymin============
SELECT a.y
FROM xyData AS a INNER JOIN xyData AS amin ON a.Site=amin.Site
WHERE a.y<=yw And amin.y<=yw
GROUP BY a.y
HAVING a.y=MAX(amin.y);
==================

and

=Qymax===========
SELECT a.y
FROM xyData AS a INNER JOIN xyData AS amax ON a.Site=amax.Site
WHERE a.y>yw And amax.y>yw
GROUP BY a.y
HAVING a.y=MIN(amax.y);
==================

they just supply the x and y values in the table that "surround" the point
(xw, yw) . The joins are much simpler and the optimizer should be able to
recognize the repetitivity of the expressions to evaluate them just once...
making the run time solution much better. You can add a condition on the
Site value in the WHERE clause of the four auxiliary queries.


The math is the same, I just re-arranged the SQL.




Hoping it runs faster,
Vanderghast, Access MVP
 
I dont get it. I open the Design View in SQL mode and pasted the code.
Then I open it back up again and the code is the same. How else can i
edit the code without opening up the Design View?

AGP


Michel Walsh said:
Hi,


"the" table is not found? Have you tried to edit the SQL statement from
the DESIGN VIEW? If so, there is a "feature" in Access that changes the SQL
code when it SHOULD not, mainly, adding a " [ ]dot " syntax here and there.
If so, try to remove the [ ] and the dot after the ] , replace them with the
original ( ), and that should do the trick... and do not edit the code
through the designer Design-view, for that query.


Hoping it may help,
Vanderghast, Access MVP


DIOS said:
Ok I tried this approach but when I enter all queries in my Access
database as 5 seperate queries, the main query does not run saying the
table is not found. So I just did a substitution in the main query
with all the smaller queries and it works although now I get a 4
records returned and Im not sure what the returned data is supposed to
give me. I get uw, xi, and eta.

AGP

"Michel Walsh" <vanderghast@VirusAreFunnierThanSpam> wrote in message
Hi,


The following should be faster ( at execution time ), but we need 5 queries.



The fifth and final query, the one you call (and it would call the four
other automatically) is:

====================================
SELECT 0.25*((1-[xi])*(1-[eta])*a.u
+(1+[xi])*(1-[eta])*b.u
+(1+[xi])*(1+[eta])*c.u
+(1-[xi])*(1+[eta])*d.u) AS uw,

2*([xw]-a.x)/(b.x-a.x)-1 AS xi,
2*([yw]-a.y)/(d.y-a.y)-1 AS eta

FROM ( SELECT x, y, u
FROM xyData
WHERE x IN( SELECT * FROM Qxmin )
AND y IN ( SELECT * FROM Qymin) ) As a,

( SELECT x, y, u
FROM xyData
WHERE x IN( SELECT * FROM Qxmax )
AND y IN ( SELECT * FROM Qymin) ) As b,

( SELECT x, y, u
FROM xyData
WHERE x IN( SELECT * FROM Qxmax )
AND y IN ( SELECT * FROM Qymax) ) As c,

( SELECT x, y, u
FROM xyData
WHERE x IN( SELECT * FROM Qxmin )
AND y IN ( SELECT * FROM Qymax) ) As d
==================================



The four other query, Qxmin, Qxmax, Qymin and Qymax are the ones we call in
the WHERE statements. Here their code:


=Qxmax==========
SELECT a.x
FROM xyData AS a INNER JOIN xyData AS amax ON a.Site=amax.Site
WHERE a.x>xw And amax.x>xw
GROUP BY a.x
HAVING a.x=MIN(amax.x);
=================

=Qxmin===========
SELECT a.x
FROM xyData AS a INNER JOIN xyData AS amin ON a.Site=amin.Site
WHERE a.x<=xw And amin.x<=xw
GROUP BY a.x
HAVING a.x=MAX(amin.x);
==================

=Qymin============
SELECT a.y
FROM xyData AS a INNER JOIN xyData AS amin ON a.Site=amin.Site
WHERE a.y<=yw And amin.y<=yw
GROUP BY a.y
HAVING a.y=MAX(amin.y);
==================

and

=Qymax===========
SELECT a.y
FROM xyData AS a INNER JOIN xyData AS amax ON a.Site=amax.Site
WHERE a.y>yw And amax.y>yw
GROUP BY a.y
HAVING a.y=MIN(amax.y);
==================

they just supply the x and y values in the table that "surround" the point
(xw, yw) . The joins are much simpler and the optimizer should be able to
recognize the repetitivity of the expressions to evaluate them just once...
making the run time solution much better. You can add a condition on the
Site value in the WHERE clause of the four auxiliary queries.


The math is the same, I just re-arranged the SQL.




Hoping it runs faster,
Vanderghast, Access MVP
 
The message is "The Microsoft Jet database engine cannot find the
input table or query 'SELECT x, y, u FROM xyData WHERE x IN( SELECT *
FROM Qxmin ) AND y IN ( SELECT * FROM Qymin)'".

The SQl take out of the designer is as fllows:
SELECT 0.25*((1-[xi])*(1-[eta])*a.u+(1+[xi])*(1-[eta])*b.u+(1+[xi])*(1+[eta])*c.u+(1-[xi])*(1+[eta])*d.u)
AS uw, 2*([xw]-a.x)/(b.x-a.x)-1 AS xi, 2*([yw]-a.y)/(d.y-a.y)-1 AS eta
FROM (SELECT x, y, u FROM xyData WHERE x IN( SELECT * FROM Qxmin )
AND y IN ( SELECT * FROM Qymin) ) AS a, (SELECT x, y, u FROM xyData
WHERE x IN( SELECT * FROM Qxmax ) AND y IN ( SELECT * FROM Qymin) )
AS b, (SELECT x, y, u FROM xyData WHERE x IN( SELECT * FROM Qxmax )
AND y IN ( SELECT * FROM Qymax) ) AS c, (SELECT x, y, u FROM xyData
WHERE x IN( SELECT * FROM Qxmin ) AND y IN ( SELECT * FROM Qymax) )
AS d;

I changed all the square brackets to parenthesis and it worked!!! yet
when I reopen the qury in the designer the brackets are back. So
everytime i edit the query i have to make sure the brackets are
replaced with parenthesis. Weird. let me test some more since im going
to be actually calling the queries through code rather than through
the query designer.

AGP
 
Hi,


You can modify the SQL code by doing some manipulation in the design
view, or by typing directly the SQL statement in the SQL view. When the
query contains ... FROM ( SELECT .... ) , it is generally preferable to
NOT modify it in the design view, but only in the SQL view, with Jet. That
restriction is not applicable for MS SQL Server, where you can still edit in
the design view, without problem, even in that case.





Vanderghast, Access MVP
 
Hi,

I am glad it worked.

Indeed, with ... FROM ( SELECT ... ), this is a known bug... you have to
edit the SQL statement in the SQL view only. If you edit it from the design
view, you are ... done. And that applies only for Jet (the design interface
with MS SQL Server does not have that bug).


Vanderghast, Access MVP
 
Well Im running some tests that are limited to certain sites and I am
getting multiple records back. If I do not specicfy the site i get
even more records back. I follow your interpolation math but the SQL
query is a little bit over my head and im trying to grasp what its
doing. The 4 auxiliaries are providing the max and mins for my two
variables and then my main query will do the interpolation correct?
Why then do i get multiple records back. They look to be repeated as
well.

AGP

Michel Walsh said:
Hi,

I am glad it worked.

Indeed, with ... FROM ( SELECT ... ), this is a known bug... you have to
edit the SQL statement in the SQL view only. If you edit it from the design
view, you are ... done. And that applies only for Jet (the design interface
with MS SQL Server does not have that bug).


Vanderghast, Access MVP

DIOS said:
The message is "The Microsoft Jet database engine cannot find the
input table or query 'SELECT x, y, u FROM xyData WHERE x IN( SELECT *
FROM Qxmin ) AND y IN ( SELECT * FROM Qymin)'".

The SQl take out of the designer is as fllows:
SELECT 0.25*((1-[xi])*(1-[eta])*a.u+(1+[xi])*(1-[eta])*b.u+(1+[xi])*(1+[eta])*c.u+(
1-[xi])*(1+[eta])*d.u)
AS uw, 2*([xw]-a.x)/(b.x-a.x)-1 AS xi, 2*([yw]-a.y)/(d.y-a.y)-1 AS eta
FROM (SELECT x, y, u FROM xyData WHERE x IN( SELECT * FROM Qxmin )
AND y IN ( SELECT * FROM Qymin) ) AS a, (SELECT x, y, u FROM xyData
WHERE x IN( SELECT * FROM Qxmax ) AND y IN ( SELECT * FROM Qymin) )
AS b, (SELECT x, y, u FROM xyData WHERE x IN( SELECT * FROM Qxmax )
AND y IN ( SELECT * FROM Qymax) ) AS c, (SELECT x, y, u FROM xyData
WHERE x IN( SELECT * FROM Qxmin ) AND y IN ( SELECT * FROM Qymax) )
AS d;

I changed all the square brackets to parenthesis and it worked!!! yet
when I reopen the qury in the designer the brackets are back. So
everytime i edit the query i have to make sure the brackets are
replaced with parenthesis. Weird. let me test some more since im going
to be actually calling the queries through code rather than through
the query designer.

AGP
 
Hi,


You are absolutely right, the four auxiliaries provide the max and the
min. You should add the site condition in those queries AND in the top most
query, just like:

....
FROM ( SELECT x, y, u
FROM xyData
WHERE x IN( SELECT * FROM Qxmin )
AND y IN ( SELECT * FROM Qymin)
AND Site=TheSite ) As a,



Each of these virtual tables,

SELECT x, y, u
FROM xyData
WHERE x IN( SELECT * FROM Qxmin )
AND y IN ( SELECT * FROM Qymin)
AND Site=TheSite

should return just one record. If not, there is probably a duplicated
(Site, x, y) value, but you can still add a DISTINCT:

SELECT DISTINCT x, y, u
FROM xyData
WHERE x IN( SELECT * FROM Qxmin )
AND y IN ( SELECT * FROM Qymin)
AND Site=TheSite




Hoping it may help,
Vanderghast, Access MVP

DIOS said:
Well Im running some tests that are limited to certain sites and I am
getting multiple records back. If I do not specicfy the site i get
even more records back. I follow your interpolation math but the SQL
query is a little bit over my head and im trying to grasp what its
doing. The 4 auxiliaries are providing the max and mins for my two
variables and then my main query will do the interpolation correct?
Why then do i get multiple records back. They look to be repeated as
well.

AGP

"Michel Walsh" <vanderghast@VirusAreFunnierThanSpam> wrote in message
Hi,

I am glad it worked.

Indeed, with ... FROM ( SELECT ... ), this is a known bug... you have to
edit the SQL statement in the SQL view only. If you edit it from the design
view, you are ... done. And that applies only for Jet (the design interface
with MS SQL Server does not have that bug).


Vanderghast, Access MVP

DIOS said:
The message is "The Microsoft Jet database engine cannot find the
input table or query 'SELECT x, y, u FROM xyData WHERE x IN( SELECT *
FROM Qxmin ) AND y IN ( SELECT * FROM Qymin)'".

The SQl take out of the designer is as fllows:
SELECT
0.25*((1-[xi])*(1-[eta])*a.u+(1+[xi])*(1-[eta])*b.u+(1+[xi])*(1+[eta])*c.u+(
1-[xi])*(1+[eta])*d.u)
AS uw, 2*([xw]-a.x)/(b.x-a.x)-1 AS xi, 2*([yw]-a.y)/(d.y-a.y)-1 AS eta
FROM (SELECT x, y, u FROM xyData WHERE x IN( SELECT * FROM Qxmin )
AND y IN ( SELECT * FROM Qymin) ) AS a, (SELECT x, y, u FROM xyData
WHERE x IN( SELECT * FROM Qxmax ) AND y IN ( SELECT * FROM Qymin) )
AS b, (SELECT x, y, u FROM xyData WHERE x IN( SELECT * FROM Qxmax )
AND y IN ( SELECT * FROM Qymax) ) AS c, (SELECT x, y, u FROM xyData
WHERE x IN( SELECT * FROM Qxmin ) AND y IN ( SELECT * FROM Qymax) )
AS d;

I changed all the square brackets to parenthesis and it worked!!! yet
when I reopen the qury in the designer the brackets are back. So
everytime i edit the query i have to make sure the brackets are
replaced with parenthesis. Weird. let me test some more since im going
to be actually calling the queries through code rather than through
the query designer.

AGP
 
Back
Top