1

重複の可能性:
その場でテーブルを作成するためのデータベース設計

データベース内にデータベースを作成する必要があります。この質問はこれに関連してます。私がやろうとしていることを詳細に説明し、コードで例を示します。基本的に、データベースに動的テーブルを作成できるようにしたいと考えています。たとえば、ユーザーが列とデータを含む独自のテーブルを作成できる Web ページを用意します。私が思いついたデータベース設計は次のとおりです。

aColumn
aDataType
aRow
aTable
zBit
zDateTime
zMoney
zNumber
zText

a で始まるテーブルはz、int、datetime 値などの特定のデータが入るデータです。aColumn は、特定のテーブルに属する列です。aRow は、aTable 内の特定の行を識別します。データベースの設計は次のとおりです。

aTable: Id, name
aColumn: Id, Name, aTable, aDataType
aDataType: Id, Name
aRow: Id, aTable
zBit: Id, aRow, aColumn, Data(Bit)
zDateTime: Id, aRow, aColumn, Data (DateTime)
zMoney: Id, aRow, aColumn, Data (Money)
zNumber: Id, aRow, aColumn, Data (INT)
zText: Id, aRow, aColumn, Data (nvarchar(MAX))

これを起動して実行するために使用したサンプルデータを次に示します。

テーブル

Id          Name
1           Users

aColumns

Id          Name           aTable       aDataType
1           Name           1            2
2           UserId         1            1
3           Occupation     1            2

aDataType

Id          Name
1           Number
2           Text

Id          aTable
1           1
2           1

Id          aRow           aColumn      Data
1           1              1            1245
2           2              2            56

文章

Id          aRow           aColumn      Data
1           1              1            Sara
2           2              1            Jake

他のすべての z* テーブルは空白です

動的テーブルを作成するクエリは次のとおりです。

select t.[Id] as [Table], c.Name as [Column], dt.Name as [DataType], r.[Id] as [Row], cast(v.Data as nvarchar(MAX)) as Data from [pod].[dbo].[aTable] t
INNER JOIN [pod].[dbo].[aColumn] c on t.Id = c.[aTable]
INNER JOIN [pod].[dbo].[aDataType] dt on c.[aDataType] = dt.Id
INNER JOIN [pod].[dbo].[aRow] r on t.[Id] = r.[aTable]
INNER JOIN [pod].[dbo].[zBit] v on c.[Id] = v.aColumn and r.[Id] = v.[aRow]
UNION ALL
select t.[Id] as [Table], c.Name as [Column], dt.Name as [DataType], r.[Id] as [Row], cast(v.Data as nvarchar(MAX)) as Data from [pod].[dbo].[aTable] t
INNER JOIN [pod].[dbo].[aColumn] c on t.Id = c.[aTable]
INNER JOIN [pod].[dbo].[aDataType] dt on c.[aDataType] = dt.Id
INNER JOIN [pod].[dbo].[aRow] r on t.[Id] = r.[aTable]
INNER JOIN [pod].[dbo].[zDateTime] v on c.[Id] = v.aColumn and r.[Id] = v.[aRow]
UNION ALL
select t.[Id] as [Table], c.Name as [Column], dt.Name as [DataType], r.[Id] as [Row], cast(v.Data as nvarchar(MAX)) as Data from [pod].[dbo].[aTable] t
INNER JOIN [pod].[dbo].[aColumn] c on t.Id = c.[aTable]
INNER JOIN [pod].[dbo].[aDataType] dt on c.[aDataType] = dt.Id
INNER JOIN [pod].[dbo].[aRow] r on t.[Id] = r.[aTable]
INNER JOIN [pod].[dbo].[zMoney] v on c.[Id] = v.aColumn and r.[Id] = v.[aRow]
UNION ALL
select t.[Id] as [Table], c.Name as [Column], dt.Name as [DataType], r.[Id] as [Row], cast(v.Data as nvarchar(MAX)) as Data from [pod].[dbo].[aTable] t
INNER JOIN [pod].[dbo].[aColumn] c on t.Id = c.[aTable]
INNER JOIN [pod].[dbo].[aDataType] dt on c.[aDataType] = dt.Id
INNER JOIN [pod].[dbo].[aRow] r on t.[Id] = r.[aTable]
INNER JOIN [pod].[dbo].[zMoney] v on c.[Id] = v.aColumn and r.[Id] = v.[aRow]
UNION ALL
select t.[Id] as [Table], c.Name as [Column], dt.Name as [DataType], r.[Id] as [Row], cast(v.Data as nvarchar(MAX)) as Data from [pod].[dbo].[aTable] t
INNER JOIN [pod].[dbo].[aColumn] c on t.Id = c.[aTable]
INNER JOIN [pod].[dbo].[aDataType] dt on c.[aDataType] = dt.Id
INNER JOIN [pod].[dbo].[aRow] r on t.[Id] = r.[aTable]
INNER JOIN [pod].[dbo].[zNumber] v on c.[Id] = v.aColumn and r.[Id] = v.[aRow]
UNION ALL
select t.[Id] as [Table], c.Name as [Column], dt.Name as [DataType], r.[Id] as [Row], cast(v.Data as nvarchar(MAX)) as Data from [pod].[dbo].[aTable] t
INNER JOIN [pod].[dbo].[aColumn] c on t.Id = c.[aTable]
INNER JOIN [pod].[dbo].[aDataType] dt on c.[aDataType] = dt.Id
INNER JOIN [pod].[dbo].[aRow] r on t.[Id] = r.[aTable]
INNER JOIN [pod].[dbo].[zText] v on c.[Id] = v.aColumn and r.[Id] = v.[aRow]

このクエリの 1 つのチャンクを次に示します。

select t.[Id] as [Table], c.Name as [Column], dt.Name as [DataType], r.[Id] as [Row], cast(v.Data as nvarchar(MAX)) as Data from [pod].[dbo].[aTable] t
INNER JOIN [pod].[dbo].[aColumn] c on t.Id = c.[aTable]
INNER JOIN [pod].[dbo].[aDataType] dt on c.[aDataType] = dt.Id
INNER JOIN [pod].[dbo].[aRow] r on t.[Id] = r.[aTable]
INNER JOIN [pod].[dbo].[zText] v on c.[Id] = v.aColumn and r.[Id] = v.[aRow]

ここでわかるように、データ (z* テーブル) は行と列によって識別されます。このクエリを実行すると、次のようになります。

結果

Table       Column         DataType     Row           Data
1           UserId         Number       1             1245          
1           UserId         Number       2             56
1           Name           Text         1             Sara
1           Name           Text         2             Jake

ここに、私の望ましい結果があります:(列が不明な場合、これらの行を列に変換する方法がわかりません)

Row         UserId       Name
1           1245         Sara
2           56           Jake

大きな問題 このテーブルには 3 つの列があると想定されていることを覚えていますか?

aColumns

Id          Name           aTable       aDataType
1           Name           1            2
2           UserId         1            1
3           Occupation     1            2

したがって、最終的に期待される結果は次のとおりです。

Row         UserId       Name         Occupation
1           1245         Sara         NULL
2           56           Jake         NULL

結果では、列も並べ替える必要があります。これは可能ですか?この種の機能をサポートするデータベース。私は、これを行うことができるデータベースに対して広くオープンです。

4

2 に答える 2

3

次に、データのエンティティ属性値モデル (EAV)の設計を検討することをお勧めします。

基本的に、テーブル名を持つテーブルと、テーブルに関するその他のメタデータを持つことができます。

次に、これらの行ごとにテーブルを作成して、データ型や名前などの列データを含めることができます。

次に、各列の値を長いテーブルに入れるテーブルがあります。

これにより、テーブルを動的に作成したり、行を動的に追加/削除したりできます。

リレーショナルと EAV の比較については、次の質問を参照してください。

エンティティ属性値データベースと厳密なリレーショナル モデルの e コマース

ただし、このデータのリレーショナル ビューが必要な場合は、ビューを最新の状態に保つためにトリガーを作成する必要があります。リレーショナル ビューが必要ない場合は、問題ありません。

これを行う別の方法は、NoSQL データベース ( http://en.wikipedia.org/wiki/NoSQL ) を使用することです。スキーマを設定する必要がないため、その行に必要な列を格納するだけで済みます。 .

この時点では、機能するデータベースが多数あり、必要な再発明が最小限であるため、NoSQL の方法を使用します。

于 2012-08-26T15:50:26.003 に答える
1

質問の最後の部分では、EAVスキーマに対してクロス集計表クエリを実行する方法を尋ねています。SQL標準の拡張機能を介してこれをサポートするデータベースもあれば、まったくサポートしないデータベースもあります。移植性のためにあなたはあなたのアプリでそれをしなければなりません。PostgreSQLは、このためのtablefunc拡張機能でクロス集計機能を提供します。

EAVパスをたどると、遅かれ早かれ後悔するでしょう。これは特定の限られた状況で役立ちますが、リレーショナルモデルには不向きであり、多くの苦痛と問題を引き起こします。特に、パフォーマンスがひどい場合があります。

代わりに検討してください:

  • 可能であれば、動的スキーマが不要になるように再設計してください。明示的な要件はWebベースのデータベースアプリのユーザー編集可能なスキーマであるため、おそらくあなたのケースでは不可能ですが、ほとんどの場合、これは正しい選択です。

  • ALTER TABLE、などを使用してスキーマを動的に作成/削除しますCREATE TABLE。一部のデータベースは、他のデータベースよりもはるかに優れています。PostgreSQLのトランザクションDDLは大いに役立ちます。これがパフォーマンスとメンテナンスの悪夢になるのを避けるために注意が必要ですが、動的構造でリレーショナルデータベースをモデル化しようとしている場合は、おそらくこれが最も賢明なオプションです。

  • EAVのようなクエリ用に最適化されたキー/値ストア。Key/Valueストアを参照してください。注意してください。これらのシステムの多くは完全なACIDセマンティクスを提供しておらず、クエリ言語が制限されている可能性があるため、アプリケーションでさらに多くの作業を行うことができます。

  • XMLまたはJSONをデータベースに保存します。リレーショナルDBを使用してこれを行うことはできますが、ドキュメントデータベースを使用した方がよい場合があります。K/Vストアと同じ注意事項が適用されます。このアプローチは、アプリですべてのクエリロジックを実行していて、データサイズがそれほど大きくない場合は問題なく機能します。

  • PostgreSQLのようなデータベース固有の機能を使用してhstore、必要に応じて任意のキー/値ストレージをサポートし、k/vが不要な場合は標準のリレーショナル設計を使用します。リレーションを出力として必要な場合でも、非効率的なクロス集計クエリと結合を伴う主要なPITAです。

クリスは良い点を述べています:あなたの全体のデザインは非常に疑わしいです。参照:内部プラットフォーム効果TDWTFがそれを引き受けます。真剣に、そこに行かないでください。

于 2012-08-27T02:00:17.373 に答える