需要帮助思考如何规范化一些混乱的数据

时间:2009-12-10 22:01:49

标签: database ms-access

我在Access表中有一些数据。我精通Access,并在此实例中使用它,因为它具有报告生成质量和非技术熟练程度的易用性。这是我唯一可以使用的工具。 数据作为一个带有大量垃圾的.xls来到我身边,基本上到处都是。我做了一堆查询来摆脱垃圾并重新组织(这在Access中要比Excel容易得多)。

然而,这就是我被困住的地方。这就是我现在所拥有的:

Name | Test Date | Test data  
Jane | ----------| --------  
-----| 3/10/09   | --------  
-----| --------- | 1  
-----| --------- | 2  
-----| --------- | 3  
John | ----------| ------  
-----| 3/12/09   | ------   
-----| --------- | 3  
-----| --------- | 1  
-----| --------- | 5  
-----| 3/13/09   | ------  
-----| --------- | 2  
-----| --------- | 5  
-----| --------- | 7  

这就是我想要的:

Name | Test Date | Test data  
Jane | 3/10/09   | 1  
Jane | 3/10/09   | 2   
Jane | 3/10/09   | 3  
John | 3/12/09   | 3  
John | 3/12/09   | 1  
John | 3/12/09   | 5  
John | 3/13/09   | 2  
John | 3/13/09   | 5  
John | 3/13/09   | 7  

某些名称下面有一个以上的测试。尽管所有测试都有12行数据,但无法预测多少或哪些名称。但您需要查看数据以了解哪些名称和日期与哪些数据相关。

我知道理想情况下你会在他们自己的表中拥有名字和测试日期,但我正在努力使这个单桌交易易于使用,而不是我的人可以使用导入和运行查询(基本上只使用宏一次点击)但不是很多。

我可以制作并运行一堆查询和表单来执行此操作,但我似乎无法弄清楚哪些。有没有人有任何想法?

7 个答案:

答案 0 :(得分:3)

  

我正试图让它成为一张桌子   处理易用的人   不是我会导入的   并运行查询。

或许最好让多个表对其进行规范化,然后为其他人创建视图?

答案 1 :(得分:2)

如果您有一个包含这些行的顺序的键字段,我建议您逐步使用VBA并构建一个新表。

答案 2 :(得分:1)

我建议将其永久转换为您喜欢的形式,但即使如此,也应该可以在使用三角形连接的直接Access查询中执行此操作,以查找最高的先前非空白行。当然,您需要有一个row_id来保留行顺序 - 如果不这样,数据将无法解释。

SELECT *
FROM tbl AS test_data
INNER JOIN (
    SELECT test_data.row_id, MAX(name_data.row_id) AS name_row_id
    FROM tbl AS test_data
    INNER JOIN tbl AS name_data
        ON name_data.row_id < test_data.row_id
        AND name_data.name IS NOT NULL -- or whatever your empty columns contain
    GROUP BY test_data.row_id
) AS name_row_id
ON name_id.row_id = tbl.row_id
INNER JOIN (
    SELECT test_data.row_id, MAX(date_data.row_id) AS date_row_id
    FROM tbl AS test_data
    INNER JOIN tbl AS date_data
        ON date_data.row_id < test_data.row_id
        AND date_data.[test date] IS NOT NULL -- or whatever your empty columns contain
    GROUP BY test_data.row_id
) AS date_row_id
INNER JOIN tbl AS name_data
    ON name_data.row_id = name_row_id.name_row_id
INNER JOIN tbl AS date_data
    ON date_data.row_id = date_row_id.date_row_id
WHERE test_data.[test data] IS NOT NULL -- or whatever your empty columns contain

答案 3 :(得分:1)

您绝对应该将数据模型与用户的关注点隔离开来。如果不这样做,您将创建一个非常难以管理,调整和升级的数据模型。 “用户友好”注意事项通常可以通过让他们访问视图而不是让他们查询原始表来轻松解决。

如果您想(真正)规范化您的数据,我猜您必须执行以下步骤:

  1. 创建表格
  2. 传输数据
  3. 创建视图
  4. 创建表格

    table_person (id_person PK, namePerson)
    table_test (id_test PK, id_Person FK, dateTest)
    table_result (id_result PK, id_test FK, valueResult)
    

    此数据模型考虑了(a)Table_PersonTable_test以及(b)Table_testTable_result之间的1对多关系。

    传输数据

    完成此操作后,您将不得不编写一些与此类似的vba代码(我假设您的原始表名为table_data,并且记录正确排序以匹配您的示例!):

    Dim rsData as DAO.recordset, _
        rsperson as DAO.recordset, _
        rsTest as DAO.recordset, _
        rsResult as DAO.recordset
    
    set rsData = currentDb.openRecordset("Table_Data")
    set rsPerson = currentDb.openRecordset("Table_Persone")
    set rsTest = currentDb.openRecordset("Table_Test")
    set rsResult = currentDb.openRecordset("Table_result")
    
    rsData.moveFirst
    Do while not rsData.eof
    
        'person is already known
        if isnull(rsData.fields("name") or _
            rsData.fields("name") = rsPerson.fields("name") Then
    
            'test reference is already known
            if isnull(rsData.fields("test date") or _
                rsData.fields("test date") = rsPerson.fields("dateTest") Then
                'add new result record
                rsResult.addNew
                rsResult.fields("id_Result") = ... (your choice of a PK(*))
                rsResult.fields("id_Test") = rsTest.fields("id_test")
                rsresult.fields("valueResult") = rsData.fields("Test data")
                rsResult.update
    
            Else
    
                'add new test record
                rsTest.addNew
                rsTest.fields("id_Test") = ... (your choice of a PK(*))
                rsTest.fields("id_Person") = rsPerson.fields("id_Person")
                rsTest.fields("dateTest") = rsData.fields("Test date")
                rsTest.update
    
            Endif
        Else
    
            'add new person record
            rsPerson.addNew
            rsPerson.fields("id_Person") = ... (your choice of a PK(*))
            rsPerson.fields("namePerson") = rsData.fields("name"
            rsPerson.update
    
        Endif
        rsData.moveNext
    loop
    ''close your recordsets and you're ok
    

    PK(*):根据您的主键选择,您可能不需要通过代码生成它。如果将表设置为(例如)自动增量编号为PK,则Access将在记录集更新时自动生成相应的值。

    创建视图

    您的视图将允许您的用户以“友好”的方式访问数据:

    SELECT table_person.namePerson, table_test.dateTest, table_result.valueResult FROM tbl_person LEFT OUTER JOIN ...
    

答案 4 :(得分:0)

至少你需要在桌子上有一个自动编号列。这是您能够最终实现记录的唯一方法。然后,您将要为父ID添加另一列。然后,您将通过查找名称字段中具有名称的下一个记录并将其自动标识号放入字段中来填充此内容。然后,您需要使用子记录中的数据更新父记录,该记录将父级中的id字段加入到子级中的parentid字段中。所有这一切都假设数据以正确的顺序进入表中,我不确定它是否没有看到数据看起来像是什么或者如何将它放入。

答案 5 :(得分:0)

对于初学者来说,如果你在数据库中有这个,你应该增加row_id来保持记录的顺序。将其放入Excel并“复制”可能实际上更容易。

答案 6 :(得分:0)

在Excel电子表格中运行此VBA代码,就像您的第一个表格一样,将生成您的第二个表格。也许,从Access导出到csv,导入到Excel,运行宏然后导出到csv并重新导入到Access。

尝试一下,将上面的示例表放在Excel工作簿的Sheet1中,运行宏,结果将显示在sheet2中。如果运行实际表,请将下面代码中的常量“16”替换为表中的实际行数。

Sub Normalize()

  Dim row, row2 As Integer
  Dim name, dt, test As String
  Dim wname, wdt, wtest As String

  row = 2
  row2 = 1

  While row < 16
    name = Sheet1.Cells(row, 1).value
    dt = Sheet1.Cells(row, 2).value
    test = Sheet1.Cells(row, 3).value
    If name <> "" Then
        wname = name
        wdt = ""
        wtest = ""
    End If
    If dt <> "" Then
        wdt = dt
        wtest = ""
    End If
    If test <> "" Then wtest = test
    If wname <> "" And wdt <> "" And wtest <> "" Then
        Sheet2.Cells(row2, 1).value = wname
        Sheet2.Cells(row2, 2).value = wdt
        Sheet2.Cells(row2, 3).value = wtest
        row2 = row2 + 1
    End If
    row = row + 1
  Wend

End Sub