每个列分别比UNION更有效地重构数据的方法? (访问限制)

时间:2014-04-09 23:48:33

标签: sql ms-access

我有一个表(200行* 77列),必须在包含4列的表中重新构建。 UNION应该可以实现的东西,但我最终得到75个UNION语句,msAccess2007除外。此外,构建即使在Excel中将代码连接在一起也很烦人。 (如果我在两个块中运行我的代码,它可以正常工作。)

那么有没有办法让代码更短,以便Access可以处理它并且更容易编写?

示例数据

ID      Var1_1  Var2_1  Var2_2      Var2_3
C2816   45654           5.050551    4.050
B2811           5.98    
C2814   453     1.52        
C2819   4               3.06141     6.8845
B291    53                          2.2

结果应该是什么样的

ID      ContentGroup Content    Volume
C2816   Var1         Var1_1     45654
C2816   Var2         Var2_2     5.050505051
C2816   Var2         Var2_3     4.05
B2811   Var2         Var2_2     5.98
C2814   Var1         Var1_1     453
C2814   Var2         Var2_1     1.52

示例代码

SELECT [tbl].ID, "Var1" AS ContentGroup, "Var1_1" AS Content, [tbl]![Var1] AS Volume 
FROM tbl 
WHERE ((([tbl]![Var1_1]) Is Not Null)) 
UNION 
SELECT [tbl].ID, "Var2" AS ContentGroup, "Var2_1" AS Content, [tbl]![Var2_1] AS Volume 
FROM tbl 
WHERE ((([tbl]![Var2_1]) Is Not Null)) 
UNION 
SELECT [tbl].ID, "Var2" AS ContentGroup, "Var2_2" AS Content, [tbl]![Var2_2] AS Volume 
FROM tbl 
WHERE ((([tbl]![Var2_2] Is Not Null)) 
UNION 
SELECT [tbl].ID, "Var" AS ContentGroup, "Var2_3" AS Content, [tbl]![Var2_3] AS Volume 
FROM tbl 
...

我尝试了SELECT * FROM(所有联合)WHERE(内容不是空);这不是解决方案,不工作,也不容易构建。

我正在考虑选择以Var开头的列,取varname AS ContentGroup的前4个字符,varname AS Content,但我不知道如何做到这一点。

2 个答案:

答案 0 :(得分:0)

我认为这里没有真正的捷径。

  1. 你可以将它分解为多个选择而不是所有联合中的一个选择,并将其插入到新的表结构中,而不是一次性插入。在这种情况下,我更喜欢单独的插入选择,而不是所有工会。

  2. 如果由于某种原因你想要所有的工会,你可以导出到SQL Server并进行操作并导回。 SQL Server没有UNION限制。

  3. 你可以用可怕的CASE结构做到这一点,但我不会。

  4. 在SQL Server中,您可以在游标中构造和执行动态sql,但这并不比使用excel构建语句更好,如果它不是一个经常可重复的过程。

    < / LI>

答案 1 :(得分:0)

因为你这样做了,所以你可以这样做。将您的数据放入Excel(xlsx,而不是xls)。

我在这段程序中写了一段时间来回收Excel中的数据,因为我收到了大量这样的数据。此函数将执行的操作与创建多个合并范围( alt + d p )时相同,然后双击Grand右下角的总细胞数。

我在那里有一个额外的位,分开&#34; |&#34;并创建新列,因为有时我有很多东西唯一IDing记录(网站和日期..)

当您运行它时,系统会提示您选择范围(所有数据),然后按Enter键。它会将这些数据转换为数据透视表,并显示详细信息&#34;为您的拨款总额。然后它将删除数据透视表表,并为您提供新的标准化数据。

看起来不错时,请将其重新导入访问权限。您可以使用left功能转换Var1_1 - &gt; Var1

鉴于您的数据,这是我得到的结果

Row Column  Value
B2811   Var1_1  5.98
B2811   Var2_1  
B2811   Var2_2  
B2811   Var2_3  
B291    Var1_1  53
B291    Var2_1  2.2
B291    Var2_2  
B291    Var2_3  
C2814   Var1_1  453
C2814   Var2_1  1.52
C2814   Var2_2  
C2814   Var2_3  
C2816   Var1_1  45654
C2816   Var2_1  5.050551
C2816   Var2_2  4.05
C2816   Var2_3  
C2819   Var1_1  4
C2819   Var2_1  3.06141
C2819   Var2_2  6.8845
C2819   Var2_3  

Sub UnpivotData()
    Dim OBJECT_REQUIRED_ERROR As Integer, UNABLE_TO_SHOW_DETAIL_ERROR As Integer
    OBJECT_REQUIRED_ERROR = 424
    UNABLE_TO_SHOW_DETAIL_ERROR = 1004

    Dim sourceRange As Range, sourceSheet As Worksheet
    On Error Resume Next
    Set sourceRange = Application.InputBox("Select cell(s)", Type:=8, Title:="Select range to unpivot...")
    If Err.Number = OBJECT_REQUIRED_ERROR Then
        Exit Sub
    End If
    On Error GoTo 0
    Application.ScreenUpdating = False
    Dim fullRangeAddress As String
    fullRangeAddress = "'" & sourceRange.Worksheet.Name & "'!" & sourceRange.Address(ReferenceStyle:=xlR1C1, external:=False)

    Dim pvtchache  As PivotCache, newPivotTable As PivotTable
    Set pvtchache = sourceRange.Worksheet.Parent.PivotCaches.Create(SourceType:=xlConsolidation, SourceData:=Array(fullRangeAddress), Version:=xlPivotTableVersion14)
    Set newPivotTable = pvtchache.CreatePivotTable(TableDestination:="", DefaultVersion:=xlPivotTableVersion14)            'TableName:="PivotTable2",

    Dim pivotWorksheet As Worksheet, numberOfNewColumns As Integer, detailWorksheet As Worksheet

    Set pivotWorksheet = ActiveSheet  'the last function will make this the active worksheet as default behavior
    On Error Resume Next
    pivotWorksheet.Cells(newPivotTable.RowRange.Rows.Count + 1, newPivotTable.ColumnRange.Columns.Count + 1).ShowDetail = True    'go to the bottom right corner (grand grand total)
    If Err.Number = UNABLE_TO_SHOW_DETAIL_ERROR Then
        MsgBox "Could not find the Grand Total cell. You'll have to double click it yourself to finish."
    End If

    Set detailWorksheet = ActiveSheet
    numberOfNewColumns = Len(detailWorksheet.Range("A2")) - Len(Replace(detailWorksheet.Range("A2"), "|", ""))

    Dim i As Integer
    Do While i < numberOfNewColumns
        detailWorksheet.Columns(2).Insert
        i = i + 1
    Loop

    Dim txtToColsRange As Range
    With detailWorksheet
        Application.DisplayAlerts = False
        .Range("A1") = sourceRange.Cells(1, 1)
        Set txtToColsRange = .Range(.Range("A1"), .Range("A1").End(xlDown))
    End With
    txtToColsRange.TextToColumns DataType:=xlDelimited, _
        TextQualifier:=xlDoubleQuote, ConsecutiveDelimiter:=False, Tab:=False, _
        Semicolon:=False, Comma:=False, Space:=False, Other:=True, OtherChar:="|", _
        FieldInfo:=Array(Array(1, 1), Array(2, 1)), TrailingMinusNumbers:=True

    detailWorksheet.Cells.EntireColumn.AutoFit

    pivotWorksheet.Delete
    Application.DisplayAlerts = True
    Application.ScreenUpdating = True
End Sub