代码之家  ›  专栏  ›  技术社区  ›  Muhammad Hasan Khan

在数据库中保存动态列表的首选方法是什么?

  •  5
  • Muhammad Hasan Khan  · 技术社区  · 16 年前

    在我们的应用程序中,用户可以创建不同的列表(如sharepoint),例如,用户可以创建汽车列表(名称、型号、品牌)和学生列表(姓名、出生日期、地址、国籍)、e.t.c。

    我们的应用程序应该能够查询列表的不同列,这样我们就不能仅仅序列化每一行并将其保存在一行中。

    我应该在运行时为每个新创建的列表创建一个新表吗?如果这是最好的解决方案,那么我想微软的SharePoint可能也会这么做?

    我应该使用以下模式吗

    Lists (Id, Name)
    ListColumns (Id, ListId, Name)
    ListRows (Id, ListId)
    ListData(RowId, ColumnId, Value)
    

    虽然一行在列表数据表中创建的行数和列表中的列数一样多,但这感觉不太对。

    你处理过这种情况吗?你在数据库里是怎么处理的?

    5 回复  |  直到 16 年前
        1
  •  1
  •   p.campbell    16 年前

    CREATE TABLE 这些实体/名单的声明?

    听起来数据库结构或模式可以在运行时更改,或者在用户的命令下更改,所以这样做可能有帮助吗?

    • 用户定义属性(屏幕大小、CpuSpeed、AmountRAM、NumberOfCores)
    • 系统允许用户在UI中创建
    • 系统通常允许它们都是字符串,除非可以判断何时所有提供的值都是日期或数字。
    • 构建CREATE脚本,对DB执行它们。
    • 将用户定义的数据插入到新表中。

    允许用户创建新实体

    下面的负面评论实际上并没有给出任何好的理由,但却制造了一点FUD。我有兴趣解决这个问题 潜在解决方案 . 我们还没有听说过规模、安全性、性能或使用情况(内部局域网和互联网)。

        2
  •  3
  •   user229044    15 年前

    你所做的被称为 EAV (Entity-Attribute-Value Model) .

    对于包含3列和1000个条目的列表:

    列表中有1条记录 ListColumns中有3条记录

    EAV模型的另一个很好的特性是,您可以轻松地合并两个列表,而不必删除和更改表。

    编辑:

    我认为您需要另一个名为ListRows的表来告诉您哪些ListData记录属于同一行!

        3
  •  2
  •   Justin    15 年前

    我以前也经历过类似的事情-我不想分享实际的表模式,所以让我们使用一些建议的表结构来做一些思考练习:

    • lists 包含所有列表的表
    • columns 包含元数据(列名)的表
    • values
    • rows 包含所有行的列表的表,否则很难计算出实际有多少行

    为了使事情简单,让一切都成为一个字符串( VARCAHR )试着提出一些问题:

    计算表中的所有行

    SELECT COUNT(*) FROM [rows]
    JOIN [lists]
        ON [rows].list_id = [Lists].id
    WHERE [Lists].name = 'Cars'
    

    嗯,还不错,相比之下:

    SELECT * FROM [Cars]
    

    在表中插入行

    BEGIN TRANSACTION
    
    DECLARE @row_id INT
    DECLARE @list_id INT
    
    SELECT @list_id = id FROM [lists] WHERE name = 'Cars'
    
    INSERT INTO [rows] (list_id) VALUES (@list_id)
    SELECT @row_id = @@IDENTITY
    
    DECLARE @column_id INT
    
    -- === Need one of these for each column ===
    SELECT @column_id = id FROM [columns]
    WHERE name = 'Make'
    AND list_id = @list_id
    
    INSERT INTO [values] (column_id, row_id, value)
    VALUES (@column_id, @row_id, 'Rover')
    
    -- === Need one of these for each column ===
    SELECT @column_id = id FROM [columns]
    WHERE name = 'Model'
    AND list_id = @list_id
    
    INSERT INTO [values] (column_id, row_id, value)
    VALUES (@column_id, @row_id, 'Metro')
    COMMIT TRANSACTION
    

    INSERT INTO [Cars] ([Make], [Model}) VALUES ('Rover', 'Metro')
    

    简单查询

    SELECT [Model] FROM [Cars] WHRE [Make] = 'Rover'
    
    SELECT [Cars].[Make], [Cars].[Model], [Owners].[Name] FROM [Cars]
    JOIN [Owners] ON [Owners].id = [Cars].owner_id
    WHERE [Owners].Age > 50
    
    SELECT [Cars].[Make], [Cars].[Model], [Owners].[Name] FROM [Cars]
    JOIN [Owners] ON [Owners].id = [Cars].owner_id
    JOIN [Addresses] ON [Addresses].id = [Owners].address_id
    WHERE [Addresses].City = 'London'
    

    我希望你开始明白。。。

    如果你需要的话 任何东西 但是对这些列表最基本的查询(字面上我的意思是“我可以拥有这个列表中的所有项目吗?”),你应该试着找一个替代品。

    只要每个用户都有自己的数据库,我肯定会推荐 CREATE TABLE 接近。即使他们没有,我还是建议你至少考虑一下。

        4
  •  1
  •   user229044    15 年前

    当用户创建列表时,绝对不应该动态创建表。数据库不是这样工作的。

    你的模式是正确的,在我看来,复数形式也是正确的,尽管我会去掉camel case并调用它们 lists , list_columns , list_rows list_data .

    我将通过跳过 rows columns 桌子,它们没用。只需在每个单元格上附加一个行/列编号,并保持稀疏:不要费心在数据库中保留空单元格。如果您保留了基于行/列的查询/排序功能,那么您的查询将(可能非常)快,因为 list_cells 将减少,并且您不必进行任何疯狂的连接来将数据链接回其表。

    以下是完整的模式:

    create table lists (
      id int primary key,
      name varchar(25) not null
    );
    
    create table list_cells (
      id int primary key,
      list_id int not null references lists(id)
        on delete cascade on update cascade,
      row int not null,
      col int not null,
      data varchar(25) not null
    );
    
        5
  •  0
  •   p.campbell    16 年前

    听起来您的环境中可能已经部署了Sharepoint。

    考虑将您的应用程序与Sharepoint集成,并将其作为您的数据存储。当您可以利用Sharepoint时,无需重新创建所有您喜欢的东西。

    这需要一些配置,但是您可以调用SP web服务来为您的列表数据创建CRUD。