【问题标题】:(Ms Access) Row_Number() Over Partition(Ms Access) Row_Number() Over Partition
【发布时间】:2017-03-07 02:21:40
【问题描述】:

如何在 MS ACCESS 上将 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;

【问题讨论】:

    标签: sql vba ms-access


    【解决方案1】:

    考虑一个可以在任何 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;
    

    【讨论】:

      【解决方案2】:

      使用 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
      

      【讨论】:

        【解决方案3】:

        任何使用OVER 子句的东西都称为窗口函数。不幸的是,MS Access 不支持窗口函数。在这种情况下,最简单的解决方案可能是回到 VBA 代码:(

        【讨论】:

        • 您知道如何使用 VBA 代码实现它吗?
        【解决方案4】:
        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
        

        【讨论】:

        • 虽然此代码可能会回答问题,但提供有关此代码为何和/或如何回答问题的额外上下文可提高其长期价值。
        猜你喜欢
        • 2018-07-25
        • 2014-03-21
        • 2018-10-16
        • 2013-02-24
        • 1970-01-01
        • 1970-01-01
        • 2018-04-02
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多