如何在MS ACCESS上使用over分区转换row_number()函数? 我想要实现的目标是:
来自此表:
ID | EntryDate
10 | 2016-10-10
10 | 2016-12-10
10 | 2016-12-31
10 | 2017-01-31
10 | 2017-03-31
11 | 2015-01-31
11 | 2017-01-31
对于此输出,仅显示每个ID的前3个最新:
ID | EntryDate
10 | 2016-12-31
10 | 2017-01-31
10 | 2017-03-31
11 | 2015-01-31
11 | 2017-01-31
在SQL Server上,我可以使用以下代码实现此目的:
select T.[ID],
T.[AptEndDate],
from (
select T.[ID],
T.[AptEndDate],
row_number() over(partition by T.[ID] order by T.[AptEndDate] desc) as rn
from Table1 as T
) as T
where T.rn <= 3;
答案 0 :(得分:4)
考虑一个可以在任何RDBMS中使用的计数相关子查询。
select T.[ID], T.[EntryDate]
from
(select sub.[ID],
sub.[EntryDate],
(select count(*) from Table1 c
where c.ID = sub.ID
and c.[EntryDate] >= sub.[EntryDate]) as rn
from Table1 as sub
) as T
where T.rn <= 3;
答案 1 :(得分:1)
使用 Top n 可能更简单,更快捷 - 正如你自己提到的那样:
Select T.[ID], T.[EntryDate]
From Table1 As T
Where T.[EntryDate] In
(Select Top 3 S.[EntryDate]
From Table1 As S
Where S.[ID] = T.[ID]
Order By S.[EntryDate] Desc)
Order By T.[ID] Asc, T.[EntryDate] Asc
答案 2 :(得分:0)
任何使用OVER
子句的东西都称为窗口函数。不幸的是,MS Access不支持窗口函数。在这种情况下最简单的解决方案可能是回到VBA代码:(
答案 3 :(得分:0)
Public Const tableName As String = "[TransactionalData$]"
Public Const parentId As String = "parentId"
Public Const elementId As String = "Id"
Public Const informationalField As String = "Label"
Sub TransactionalQuery(Optional ByVal Id As Integer = 0)
Dim rs As New ADODB.Recordset, cn As New ADODB.Connection
Dim sqlString As String
''' setup the connection to the current Worksheet --- this can be changed as needed for a different data source, this example is for EXCEL Worksheet
cn.Open ("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & ThisWorkbook.FullName & ";Extended Properties='Excel 12.0 Macro;HDR=YES;IMEX=1'")
'''' Alternate method for the query
sqlString = "SELECT ParentId, Rank() OVER(PARTITION BY ParentId ORDER BY Label) , vlu.Id, vlu.Label FROM [TransactionalData$] var LEFT JOIN [TransactionalData$] vlu ON vlu.Id=var.ParentId"
''' will need to change the TableName (TransactionalData$]
sqlString = "SELECT DISTINCT " & elementId & " FROM " & tableName & " WHERE " & parentId & " = " & Id
rs.Open sqlString, cn, adOpenStatic, adLockReadOnly
'' Start collecting the SQL UNIONs to run at the end
sqlString = ""
Do While Not rs.EOF
'' Add current Element to the UNION
sqlString = sqlString & "SELECT * FROM " & tableName & " WHERE " & elementId & " = " & rs.Fields(elementId) & " UNION " & vbCrLf
'' Add all children element to the UNION
sqlString = sqlString & subQuery(cn, rs.Fields(elementId))
rs.MoveNext
Loop
rs.Close
'''Debug.Print sqlString
''' Remove the extra UNION keyword at the end
sqlString = Left(sqlString, Len(sqlString) - 8)
''' Exectue the built query
rs.Open sqlString, cn, adOpenStatic, adLockReadOnly
''Do While Not rs.EOF
'' Debug.Print rs.Fields(elementId) & ", " & rs.Fields(informationalField)
'' rs.MoveNext
''Loop
End Sub
Function subQuery(cn As ADODB.Connection, Id As Integer) As String
Dim sqlString As String
Dim subSqlString As String, rs As New ADODB.Recordset
'' Create a list of children for the current element
sqlString = "SELECT DISTINCT " & elementId & " FROM " & tableName & " WHERE " & parentId & " = " & Id
rs.Open sqlString, cn, adOpenStatic, adLockReadOnly
'' start the SQL for current elements children
sqlString = ""
Do While Not rs.EOF
''' add in the current element to the UNION
sqlString = sqlString & "SELECT * FROM " & tableName & " WHERE Id = " & rs.Fields(elementId) & " UNION " & vbCrLf
''' recursively find additional children for the current element
sqlString = sqlString & subQuery(cn, rs.Fields(elementId))
rs.MoveNext
Loop
rs.Close
''' return the SQL for the current element and all its children
subQuery = sqlString
End Function