First, I renamed the fields because using reserved words like Year and Value makes me very nervous.
Code:
Table1
MyID
MyState
MyMethod
MyParameter
MyYear
Samples
MyValue
Second, I created a count query to get the count of records in each group, and a ranking query (qryGroupRank) to give you each record's ordinal rank within its group. Note that in case of tie Values, MyRank has an arbitrary tiebreaker to be used for calculating percentile, and MyTrueRank gives both tied records the same rank.
Code:
qryGroupCount:
SELECT
MyState,
MyMethod,
MyParameter,
MyYear,
Count(MyID) AS MyNVal
FROM
Table1
GROUP BY
MyState,
MyMethod,
MyParameter,
MyYear;
qryGroupRank:
SELECT
T1.MyID,
First(T1.MyState) AS MyState,
First(T1.MyMethod) AS MyMethod,
First(T1.MyParameter) AS MyParameter,
First(T1.MyYear) AS MyYear,
First(T1.MyValue) AS MyValue,
SUM( IIF( (T1.MyValue>T2.MyValue OR (T1.MyValue = T2.MyValue AND T1.MyID>=T2.MyID)),1,0)) AS MyRank,
SUM( IIF( (T1.MyValue>T2.MyValue),1,0)) + 1 AS MyTrueRank
FROM
Table1 AS T1
INNER JOIN
Table1 AS T2
ON ((T1.MyYear = T2.MyYear)
AND (T1.MyParameter = T2.MyParameter)
AND (T1.MyMethod = T2.MyMethod)
AND (T1.MyState = T2.MyState))
GROUP BY T1.MyID;
Third, I created a static table of the constants used to calculate percentiles given any particular group size. Here, I'm giving you the calc rather than the values, obviously. Just load enough for the largest group you anticipate.
Code:
tblNVals
NVal Number 3 thru 10 (as many records as you want)
PNum Number 90 (and any other percentiles you want)
PVal Currency (NVal-1)*PNum/100
KVal Number Int(PVal)
K1Val Number KVal+1
DVal Currency PVal-KVal
Next, for each group, we join qryGroupCount to tblNVals to get the k-numbers of the two values we need to pull, then join to qryGroupRank for the K and K+1 record, to calculate the RankValue for 90th percentile.
Code:
qryRankValsByGroup;
SELECT
QG.MyState,
QG.MyMethod,
QG.MyParameter,
QG.MyYear,
QG.MyNVal,
TN.KVal,
TN.K1Val,
TN.DVal,
Q1.MyValue,
Q2.MyValue,
(Q1.MyValue + TN.DVal*(Q2.MyValue - Q1.MyValue)) As RankValue
FROM
((qryGroupCount AS QG
INNER JOIN
tblNVals AS TN
ON TN.NVal = QG.MyNVal)
INNER JOIN
qryGroupRank AS Q1
ON (Q1.MyYear = QG.MyYear)
AND (Q1.MyParameter = QG.MyParameter)
AND (Q1.MyMethod = QG.MyMethod)
AND (Q1.MyState = QG.MyState)
AND (Q1.MyRank = TN.KVal))
INNER JOIN
qryGroupRank AS Q2
ON (Q2.MyYear = QG.MyYear)
AND (Q2.MyParameter = QG.MyParameter)
AND (Q2.MyMethod = QG.MyMethod)
AND (Q2.MyState = QG.MyState)
AND (Q2.MyRank = TN.K1Val)
WHERE PNum = 90;
These calculations run in a flash on your test database.