3

1つの行に複数の1対多の関係を持つデータを表示するために必要なAccessデータベースがあります(たとえば、アイテムが「a、b、e、f」としてリストされ、そのような複数の列があります) 。データをそのように保存することも悪い考えですが、ユーザーがこれらの列のいくつかでフィルタリングできるようにしていることを考えると、第一正規形に違反するよりもデータを処理するためのより良い方法を考えることはできません。 。

例として、私がいくつかのジャーナル記事を持っているとしましょう。それぞれが複数の動物と複数の野菜について報告している可能性があります。ユーザーは、ソース名でフィルタリングすることも、1つ以上の動物と1つ以上の野菜でフィルタリングすることもできます。出力は次のようになります

Source name....animals...............vegetables
Source 1.......dogs, cats, birds.....carrots, tomatoes
Source 2.......leopards, birds.......tomatoes, zucchini, apples
Source 3.......cats, goldfish........carrots, cucumbers

通常、ソース名+動物を含む別のテーブルがあります。

Source name......animal
Source 1.........dog
Source 1.........cats
Source 1.........birds
Source 2.........leopards

野菜の同様の表。ただし、データをユーザーに表示する方法(コンマ区切りのリスト)と、ユーザーがデータをフィルター処理する方法(犬と猫を含むソース、およびニンジンとトマトを含むソースのみを表示するようにフィルター処理する場合があります)を考慮すると、私はデータを動物と野菜のコンマ区切りリストとして保存することは理にかなっていると思います。カンマ区切りのリストを使用すると、ユーザーが複数の野菜と複数の動物を選択すると、次のように言うことができます。

WHERE (Vegetables like "*carrots*" and Vegetables like "*tomatoes*") AND (Animals like *dogs*" and Animals like "*cats*")

多くのVBAと複数のクエリを使用せずに、Accessでこれと同じ種類のクエリを実行する効率的な方法を考えることはできません。

4

3 に答える 3

4

規則に違反することが理にかなっているシナリオをいつでも構築できるため、タイトルの質問に対する答えは「はい」です。

ただし、これはそれらのシナリオの 1 つではありません。あなたが提起した検索と表示の問題は、ほとんどの 1 対多の関係 (または、少なくとも多くの1 対多の関係) に共通しており、これが第 1 正規形に違反する理由である場合、多くの正規化されたデータベース。

データベースを正しく構築すれば、カンマ、相互に埋め込まれた検索語、およびインデックスの欠如による低速検索について心配する必要はありません。カンマ区切りのロールアップを実行する再利用可能なコードを記述して、車輪の再発明を繰り返さないようにします。

于 2012-10-01T19:28:45.817 に答える
0

私はまだこれを適切に正規化します-そして、プレゼンテーションについて心配します.

Oracle では、これはユーザー定義の集計関数で行われます。

于 2012-10-01T19:28:45.843 に答える
0

フィールド参照整合性との関係で 1:1 を維持できるように、結合テーブルを構築してみませんか。それ以外の場合は、1:many フィールド値を解析して参照関連付けを取得する必要があるため、すべてが魔法のように機能します (へへへ ;))

第 1 正規形に違反する必要がある場合、答え 9:10 は、結合テーブルを作成し、目的の効果を生み出す方法を構築することです。

編集日: 2012-10-09 9:06AM

  • このデザインは、未知の量の列/フィールドに表示される未知の量の情報に対応するものでした。私は数値を対象としていますが、情報フィールドを連結して単一のデータ フィールドを生成する vba メソッドを開発するだけです。

表1

gid (Number) <- Table2.id
cid (Number) <- Table3.id
price (Number)
  • gid MANY <- ONE Table2.id
  • cid MANY <- ONE Table3.id

crt_CategoryPG

TRANSFORM Sum(Table1.price) AS SumOfprice
SELECT View1.tid, Table1.cid, View1.category
FROM Table2 INNER JOIN (View1 INNER JOIN Table1 ON View1.cid = Table1.cid) ON Table2.gid = Table1.gid
WHERE (((Table2.active)=True) AND ((View1.active)=True))
GROUP BY View1.tid, Table1.cid, View1.category, Table2.active, View1.active
ORDER BY View1.tid, Table1.cid
PIVOT [Table2].[gid] & " - " & [Table2].[nm];

CT テーブルを更新する

Public Function RefreshCategoryPricing(Optional sql As String = "")
    If HasValue(lstType) Then
Application.Echo False      'Turn off Screen Updating

        Dim cttbl As String: cttbl = CreateCTTable("crt_CategoryPG") 'Create Table to store the Cross-Tab information
        If IsNullOrEmpty(sql) Then
            sql = SQLSelect(cttbl)
        End If

        Dim flds As DAO.Recordset: Set flds = CurrentDb.OpenRecordset(sql)
        Dim fldwd As String, fldhd As String      'Store the Field Width pattern and Field Header Row
        fldhd = "-1;-1;Category"
        fldwd = "0"";0"";2.5"""   'Handles `tid`, `cid`, and `category` columns in the ListBox
        'Assign the number of columns based on the number of fields in CTtable
        lstCategoryPG.ColumnCount = flds.Fields.Count

        Dim fld As Long
        For fld = 3 To (flds.Fields.Count - 1)
            fldwd = fldwd & ";.75"""
            fldhd = fldhd & ";" & flds.Fields(fld).Name
        Next

        GC flds

        lstCategoryPG.ColumnHeads = True
        lstCategoryPG.ColumnWidths = fldwd

        sql = SQLSelect(cttbl, , ("tid = " & lstType.Value))

        lstCategoryPG.Enabled = True
        RefreshControl CurrentDb, lstCategoryPG, sql, , False
        lstCategoryPG.AddItem fldhd, 0

Application.Echo True       'Turn on Screen Updating
    End If
End Function

クロス集計表の作成

'@ct - String value, Source Cross-Tab to base Table design off of
Public Function CreateCTTable(ct As String) As String
    Dim tbl As String: tbl = "tbl_" & ct
    Dim sql As String

    If TableExists(tbl) Then
    'Table exists and needs to be dropped
        sql = SQLDrop(tbl)
        CurrentDb.Execute sql
    End If

    'Create Table
    sql = SQLSelect(ct, "* INTO " & tbl)
    CurrentDb.Execute sql

    CreateCTTable = tbl
End Function
于 2012-10-01T19:44:17.873 に答える