数据库中的数据库(表设计)

时间:2012-08-26 15:40:40

标签: mysql sql sql-server oracle postgresql

  

可能重复:
  Database design to create tables on the fly

我需要在数据库中创建数据库。此问题与this有关。我将尝试详细解释我要做的事情并在代码中提供示例。基本上,我希望能够在数据库中创建动态表。例如,我将有一个网页,允许用户使用列和数据创建自己的表。这是我提出的数据库设计:

aColumn
aDataType
aRow
aTable
zBit
zDateTime
zMoney
zNumber
zText

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))

以下是我用来启动并运行的一些示例数据:

aTable

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

AROW

Id          aTable
1           1
2           1

aNumber的

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

aText

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]

以下是此查询的一个部分:

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

大问题 这个表假设有三列记得?

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

在结果中我也需要对列进行排序。这甚至是可能的吗?哪些数据库支持此类功能。我对任何可以做到这一点的数据库都很开放。

2 个答案:

答案 0 :(得分:3)

您可能希望查看数据的Entity Attribute Value model (EAV)设计。

基本上,您可以拥有一个包含表名的表,以及表上的一些其他元数据。

然后,您可以为每个行创建一个表以获取列数据,例如数据类型和名称。

然后,您有一个表格,您可以在长表中放置每列的值。

这允许您动态创建表,或动态添加/删除行。

关于关系和EAV的比较,你可以看看这个问题:

Entity Attribute Value Database vs. strict Relational Model Ecommerce

如果您想拥有此数据的关系视图,那么您需要创建触发器以帮助保持视图的最新状态,这可能需要大量工作才能使其正常运行。如果你不需要关系视图那么你应该没事。

另一种方法是使用NoSQL数据库(http://en.wikipedia.org/wiki/NoSQL),因为不需要设置架构,因此您只需存储该行所需的列。

此时我会采用NoSQL方式,因为有许多数据库可以工作,而你需要重新发明的事情很少。

答案 1 :(得分:1)

对于问题的最后一部分,您要问的是如何针对EAV架构进行cross-tabulation查询。一些数据库通过SQL标准的扩展支持这一点,其他数据库根本不支持它。为了便于携带,您必须在应用中执行此操作。 PostgreSQL为此提供了crosstab function in the tablefunc extension

如果沿着EAV路走下去,你迟早会后悔的。它在某些有限的情况下是有用的,但它不适合关系模型并导致许多痛苦和问题,其中最重要的是可怕的性能。

改为考虑:

  • 如果可能,请重新设计,这样您就不需要动态架构了。可能在您的情况下是不可能的,因为您的明确要求是基于Web的数据库应用程序的用户可编辑模式,但在大多数情况下,这是正确的选择。

  • 使用ALTER TABLECREATE TABLE等动态创建/删除架构。有些数据库比其他数据库要好得多。 PostgreSQL的事务性DDL可以提供很多帮助。需要注意避免这成为性能和维护的噩梦,但如果您尝试使用动态结构建模关系数据库,则可能是最常用的选项。

  • 针对类似EAV的查询进行了优化的键/值存储;见Key/Value stores。请注意,许多这些系统不提供完整的ACID语义,并且可能具有有限的查询语言,因此您可以在应用程序中完成更多工作。

  • 在数据库中存储XML或JSON。您可以使用关系数据库执行此操作,但使用文档数据库可能会更好。与K / V商店相同的注意事项适用。如果您在应用中执行所有查询逻辑并且数据大小不是太大,则此方法可以正常工作。

  • 使用PostgreSQL的hstore等特定于数据库的功能来支持所需的任意键/值存储,并使用不需要k / v的标准关系设计。如果你想将关系作为输出,它仍然是一个主要的PITA,涉及低效的交叉表查询和加入。

Chris提出了一个很好的观点:你的整个设计非常可疑。请参阅:The inner platform effectTDWTF's take on it。说真的,不要去那里。