当列数据是动态的时,如何对交叉表查询中的列进行排序?

时间:2012-12-13 14:50:35

标签: ms-access sorting ms-access-2010 crosstab

我一直在对这个主题进行一些研究,我似乎无法找到一个可行的解决方案,或者一个解释得足以让我实施的解决方案。

如果您曾在Access中创建交叉表查询,则您会发现默认情况下,Access会按字母顺序对列进行排序。您可以通过转到属性对话框并按照您喜欢的顺序输入列标题来更改此订单。这是一个真正的痛苦,但正如一位回答者在另一个网站上提到的那样,“这只是一次痛苦一次!”

嗯......如果您的列是动态的,那就不是这样。就我而言,我在表格上有第二列,其中包含我想要使用该字段进行排序的列标题。我想我可以将我的排序列的详细信息附加到描述列的前面(已在其他地方建议),但我不认为这是解决问题的最优雅方法。这尤其是一个问题,因为排序信息是系统数据,对交叉表的最终用户无用。

有谁知道这个问题的解决方案?如果是这样,您是否可以拼出对交叉表查询的动态列进行排序的步骤?

我认为问题在所有常用的Access版本(Access 2003+)中都是持久的,但为了防止它产生影响,我使用的是Access 2010.


更新

这是一些非常简单的示例数据,可以帮助表达问题。我的实时场景周围还有一些其他的复杂性,但这个数据集肯定能够解决问题。

表#1 这就是标题的来源。 Key是列顺序的排序,Descriptions是交叉表中的输出标题。

+---------+---------------------------------------+
| Key     | Descriptions                          |
+---------+---------------------------------------+
| Kfsg2E  | Hey, this is accounting code X!       |
+---------+---------------------------------------+
| abR3    | This is yet another accounting code!  |
+---------+---------------------------------------+
| Gruu!   | Yet another accounting code           |
+---------+---------------------------------------+

表#2 这是数据存储 P_Key + F_Key是唯一的,两者是桌面上的主键。

+---------+---------+-------+
| P_Key   | F_Key   | Value |
+---------+---------+-------+
| 1001    |Kfsg2E   | 1.0   |
+---------+---------+-------+
| 1001    |abR3     | 1.1   |
+---------+---------+-------+
| 1001    |Gruu!    | 1.2   |
+---------+---------+-------+
| 1002    |Kfsg2E   | 2.0   |
+---------+---------+-------+
| 1002    |abR3     | 2.1   |
+---------+---------+-------+
| 1002    |Gruu!    | 2.2   |
+---------+---------+-------+
| 2001    |Kfsg2E   | 3.0   |
+---------+---------+-------+
| 2001    |abR3     | 3.1   |
+---------+---------+-------+
| 2001    |Gruu!    | 3.2   |
+---------+---------+-------+

交叉表结果 这些将导出到Excel以供用户更新。

+---------+---------------------------------+--------------------------------------+-----------------------------+
| P_Key   | Hey, this is accounting code X! | This is yet another accounting code! | Yet another accounting code |
+---------+---------------------------------+--------------------------------------+-----------------------------+
| 1001    | 1.0                             | 1.1                                  | 1.2                         |
+---------+---------------------------------+--------------------------------------+-----------------------------+
| 1001    | 2.0                             | 2.1                                  | 2.2                         |
+---------+---------------------------------+--------------------------------------+-----------------------------+
| 1001    | 3.0                             | 3.1                                  | 3.2                         |
+---------+---------------------------------+--------------------------------------+-----------------------------+

这是Access对这些列进行排序的方式。但是,我需要它看起来像下面的表格,它是Table #1中的键,而不是Description

+---------+--------------------------------------+-----------------------------+---------------------------------+
| P_Key   | This is yet another accounting code! | Yet another accounting code | Hey, this is accounting code X! |
+---------+--------------------------------------+-----------------------------+---------------------------------+
| 1001    | 1.1                                  | 1.2                         | 1.0                             |
+---------+--------------------------------------+-----------------------------+---------------------------------+
| 1001    | 2.1                                  | 2.2                         | 2.0                             |
+---------+--------------------------------------+-----------------------------+---------------------------------+
| 1001    | 3.1                                  | 3.2                         | 3.0                             |
+---------+--------------------------------------+-----------------------------+---------------------------------+

4 个答案:

答案 0 :(得分:11)

在不同时间遇到相同的场景后,我准备了一种可重复的方法,将In列表添加到PIVOT子句的末尾。这样做将按照 pivotfield In列表中元素的顺序对交叉表查询中的列进行排序。 Documentation for this construct is available from MSDN。解决方案是需要由表单或其他事件上的命令按钮触发的过程。请参阅Sub。

下方的屏幕截图
Public Sub SortPivotColumns(querynameSource As String, queryname As String, SortName As String, SortColumnNameField As String, SortIndexName As String, NonPivotFieldCount As Integer, ParamArray ParamArr() As Variant)

' This sub goes through several steps to effectively adds an In list that sorts the 'Columns' of a crosstab query in MS Access
' 13 November 2012
' E Easterly
'
' This technique uses several components.
' 1) The original unmodified cross tab query (querynameSource)
' 2) The resulting, columns-have-been-sorted query (query)
' 3) An index table which has two columns, a numeric index used for sorting and the column name
' 4) A table or query that can be joined on the column names of the cross tab query to update the index table
'    The name of the table or query would be 'SortName'
'    The field in 'SortName' that the crosstab query columns are joined against is the 'SortColumnNameField'
'    The field in 'SortName' that has the desired order is the SortIndexName
' 5) A number which specifies the count of non-pivot/row heading columns (NonPivotFieldCount)
' 6) An optional array that contains any parameters needed for the query
'
'
'   USE:
'
'   SortPivotColumns "qryCrosstab_Initial", _
'                 "qryCrosstab_Sorted", _
'                 "tblKeyDescriptions", _
'                 "Descriptions", _
'                 "NumericIndexForSorting", _
'                  1
'
'
'
'
Dim rs As DAO.Recordset
Dim db As Database
Dim fld As DAO.Field
Dim sql As String
Dim ColumnHeading As Variant
Dim qdf As QueryDef
Dim qdfSRC As QueryDef
Dim UpdateIndexSQL As Variant

DoCmd.SetWarnings False 'Turn off warnings

Set db = CurrentDb

Set qdfSRC = db.QueryDefs(querynameSource)
Set qdf = db.QueryDefs(queryname)
qdf.sql = qdfSRC.sql

If Not (IsEmpty(ParamArr)) Then
    Dim i As Integer
    For i = 0 To UBound(ParamArr)
        qdf.Parameters(i) = ParamArr(i)
    Next
End If


' First, get the list of fields from the query

Set rs = qdf.OpenRecordset

' Then, create a temporary indexing table
If Not IsNull(DLookup("Name", "MSysObjects", "Name='ttblSortCrosstabColumns' And Type In (1,4,6)")) Then
    db.Execute "DROP TABLE ttblSortCrosstabColumns"
End If

db.Execute "CREATE TABLE ttblSortCrosstabColumns (FieldIndex INTEGER , ColumnName TEXT(250))"

' And populate it with the current index and column names from queryname
  For Each fld In rs.Fields
    If fld.OrdinalPosition > (NonPivotFieldCount - 1) Then
        DoCmd.RunSQL "Insert into ttblSortCrosstabColumns VALUES(" & fld.OrdinalPosition & ", """ & fld.Name & """)"
    End If
  Next fld
  Set fld = Nothing
  rs.Close
  Set rs = Nothing


' Now, the temporary table is joined with the sort table/query and the indexes are updated
UpdateIndexSQL = ("  UPDATE ttblSortCrosstabColumns " & _
                  "  INNER JOIN " & SortName & " ON ttblSortCrosstabColumns.ColumnName=" & SortName & "." & SortColumnNameField & _
                  "  Set ttblSortCrosstabColumns.FieldIndex = [" & SortIndexName & "]")
DoCmd.RunSQL (UpdateIndexSQL)


' Then, the column headings are added to a string to prepare the In list
sql = "SELECT ttblSortCrosstabColumns.ColumnName FROM ttblSortCrosstabColumns ORDER BY ttblSortCrosstabColumns.FieldIndex"
Set rs = db.OpenRecordset(sql)
    rs.MoveFirst
    ColumnHeading = "'" & rs.Fields(0).Value & "'"
    rs.MoveNext

    Do While Not rs.EOF
    ColumnHeading = ColumnHeading & ", '" & rs.Fields(0).Value & "'"
    rs.MoveNext
    Loop

rs.Close
Set rs = Nothing
' db.Execute "DROP TABLE ttblSortCrosstabColumns"

Dim cs As Variant

' Set qdf = db.QueryDefs(queryname)   ' may not need this

' The query is updated with the In list
cs = Left$(qdf.sql, Len(qdf.sql) - 3) & " In(" & ColumnHeading & ");"

qdf.sql = cs

' Take a look at the resulting query sql by uncommenting the below section
' Debug.Print cs


DoCmd.SetWarnings True  'Turn warnings back on

End Sub

在下面的屏幕截图中,请注意tblKeyDescriptions和tblPFValues。这些来自这个问题。 qryCrosstab_Initial类似于上述问题中提供的查询。该表单用于运行该过程并打开查询之前和之后。

Screen Shot Crosstab Sorting

整数字段(NumericIndexForSorting)已添加到tblKeyDescriptions,因为sub需要一个数字索引来对列名进行排序。

Key Descriptions table with numeric index

现在,检查初始和已排序查询的SQL视图中突出显示的In列表。

SQL differences showing in PIVOT clause

这是在交叉表查询中对列进行排序所需的全部内容。动态生成In列表是sub的目的。

注意:每次运行查询时都需要运行sub,因此使用诸如命令按钮On Click事件之类的事件将序列绑定在一起是有帮助的。

答案 1 :(得分:1)

这是 不完美的 解决方案,它使用了一些Access& amp; Excel中:

  1. 制作交叉表时,请使用Table1.Key作为列。
  2. 在Excel文件中的新标签(称之为“查找”?)上,制作表#1
  3. 在Excel主文件夹的第一行(即粘贴数据集的位置)中,创建一堆Vlookup()公式以查看第2行并从查找表中提取正确的描述。< / LI>
  4. 将数据集粘贴到第2行。结果将在下表中,其中第一行实际上是一组Vlookup,它们引入了正确的列描述。
  5. 要求用户忽略或删除第2行。
  6. 我不知道您的脚本有多复杂,但如果这些数据通过自动化粘贴到Excel文件中,那么您只需隐藏第2行并跳过第6步。

        +---------+--------------------------------------+-----------------------------+---------------------------------+
        | P_Key   | This is yet another accounting code! | Yet another accounting code | Hey, this is accounting code X! |        
        +---------+--------------------------------------+-----------------------------+---------------------------------+
        |PasteHere| abR3                                 | Gruu!                       | Kfsg2E                          |
        +---------+--------------------------------------+-----------------------------+---------------------------------+
        | 1001    | 1.1                                  | 1.2                         | 1.0                             |
        +---------+--------------------------------------+-----------------------------+---------------------------------+
        | 1001    | 2.1                                  | 2.2                         | 2.0                             |
        +---------+--------------------------------------+-----------------------------+---------------------------------+
        | 1001    | 3.1                                  | 3.2                         | 3.0                             |
        +---------+--------------------------------------+-----------------------------+---------------------------------+
    

答案 2 :(得分:0)

我只是在解决这个问题。虽然提供的解决方案有效(根据描述),另一种可能的解决方案是动态创建查询 - def(如在所描述的解决方案中),但不是改变查询的SQL,只需填写查询的列标题属性动态生成的列标题字符串。 OP已经提到了列标题的工作原理,但没有提及 这似乎更容易实现,只涉及一些vba来枚举字符串中的可能值并设置属性

  • 生成交叉表querydef
  • 将列标题枚举为字符串
  • 设置属性

所以我要尝试一下,看看它是否有效

嗯....结果是列标题不是querydef的实际属性,但它会自动放入SQL中。

我以为我有一个光明的时刻;)

答案 3 :(得分:0)

如果您知道查询的预期结果并且可以预测列数,则对交叉表查询的结果进行排序的最简单方法是在属性表的“列标题”字段中指定正确的顺序。

Access Column Heading Property Sheet