相同表/类的SQL表设计

时间:2018-10-02 08:06:34

标签: c# sql sql-server data-modeling

在我的代码中,我通过创建从一个基本类“ ProjectAttribute”继承的5个类来区分“描述”项目的5种类型的属性。一个项目可以具有每种属性类型的0到x(因此在SQL中是多对多)。
这里是一些伪代码:

<main class="main aktualitasu_saraksta_konteineris" role="main">
    <?php
        $args = array(
            'post_type'             => 'post',
            'posts_per_page'        => -1,
            'group_by'              => 'date',
            'order'                 => 'DESC',
            'ignore_sticky_posts'   => 1
        );
        $query = new WP_Query($args);
    ?>

    <?php if ($query->have_posts()) : while ($query->have_posts()) : $query->the_post(); ?>
        <?php get_template_part( 'parts/loop', 'news' ); ?>
    <?php endwhile; endif; wp_reset_postdata();?>                           
</main>

每个此类都有一个不同的数据集,我想将它们存储在SQL数据库中。但是,为相同的类创建5个表会让人感到不对,这将导致另外5个链接表将其链接到另一个表(多对多)。最后,我想到了2种不同的想法

想法1
我创建了5个表以及5个链接表,将其链接到“项目”表。
感觉不对,因为每个属性表将包含大约20-30个条目,并且我必须查询5个不同的链接表才能解决此“混乱”。

想法2
我创建了一个名为“ ProjectAttrbiutes”的表,并为每种属性类型添加了另外一列。即“ IsSWAttribute”,“ IsHardwareAttrobite”。此外,我仅添加一个链接表。
听起来更好,但建议将原始数据结构缩减为一张表吗?
另一方面,我最终只需要查询一个链接表。

希望您能为我指明正确的方向。

2 个答案:

答案 0 :(得分:0)

我将为此使用4个表。

包含项目的表。

包含属性的表。

包含属性类型的表。

链接项目和属性的表

  

[Project]-> [ProjectAttribute] <-[Attribute]-> [attributeType]

对于属性类型,在MySQL和Pg​​SQL中有一些不错的类型,即枚举类型。在MS SQL中,您可以建立一个常规表。

SQL Fiddle

MS SQL Server 2017架构设置

CREATE TABLE project
(
  id INT IDENTITY PRIMARY KEY NOT NULL,
  name VARCHAR(255)
);

CREATE TABLE attributeType
(
  id INT IDENTITY PRIMARY KEY NOT NULL,
  name VARCHAR(255)
);

CREATE TABLE attribute
(
  id INT IDENTITY PRIMARY KEY NOT NULL,
  title VARCHAR(255),
  type_id INT,
  CONSTRAINT FK_attributeType FOREIGN KEY (type_id)
    REFERENCES attributeType(id)
);

CREATE TABLE ProjectAttribute
(
  project_id INT NOT NULL,
  attribute_id INT NOT NULL,
  CONSTRAINT FK_project FOREIGN KEY (project_id)
    REFERENCES project(id),
  CONSTRAINT FK_attribute FOREIGN KEY (attribute_id)
    REFERENCES attribute(id),
  CONSTRAINT pk_ProjectAttribute PRIMARY KEY (project_id, attribute_id)
);

INSERT INTO project (name) VALUES ('project 1 with hardware and software');
INSERT INTO project (name) VALUES ('project 2 with hardware only');
INSERT INTO project (name) VALUES ('project 3 with software only');

INSERT INTO attributeType (name) VALUES ('Hardware');
INSERT INTO attributeType (name) VALUES ('Software');

INSERT INTO attribute (title, type_id) VALUES ('Some hardware 1', 1);
INSERT INTO attribute (title, type_id) VALUES ('Some hardware 2', 1);
INSERT INTO attribute (title, type_id) VALUES ('Some software 1', 2);
INSERT INTO attribute (title, type_id) VALUES ('Some software 2', 2);
INSERT INTO attribute (title, type_id) VALUES ('Some hardware 3', 1);

INSERT INTO ProjectAttribute VALUES (1, 1);
INSERT INTO ProjectAttribute VALUES (1, 2);
INSERT INTO ProjectAttribute VALUES (1, 3);
INSERT INTO ProjectAttribute VALUES (1, 4);
INSERT INTO ProjectAttribute VALUES (2, 1);
INSERT INTO ProjectAttribute VALUES (2, 5);
INSERT INTO ProjectAttribute VALUES (3, 3);

查询1

SELECT * FROM project p
INNER JOIN ProjectAttribute pa
  ON p.id = pa.project_id
INNER JOIN attribute a
  ON a.id = pa.attribute_id
INNER JOIN attributeType t
  ON t.id = a.type_id

Results

| id |                                 name | project_id | attribute_id | id |           title | type_id | id |     name |
|----|--------------------------------------|------------|--------------|----|-----------------|---------|----|----------|
|  1 | project 1 with hardware and software |          1 |            1 |  1 | Some hardware 1 |       1 |  1 | Hardware |
|  1 | project 1 with hardware and software |          1 |            2 |  2 | Some hardware 2 |       1 |  1 | Hardware |
|  1 | project 1 with hardware and software |          1 |            3 |  3 | Some software 1 |       2 |  2 | Software |
|  1 | project 1 with hardware and software |          1 |            4 |  4 | Some software 2 |       2 |  2 | Software |
|  2 |         project 2 with hardware only |          2 |            1 |  1 | Some hardware 1 |       1 |  1 | Hardware |
|  2 |         project 2 with hardware only |          2 |            5 |  5 | Some hardware 3 |       1 |  1 | Hardware |
|  3 |         project 3 with software only |          3 |            3 |  3 | Some software 1 |       2 |  2 | Software |

答案 1 :(得分:0)

这是我的一个表建议(Type是一个像{Hardware,Software,...}这样的枚举-这意味着MS SQL中ID为Type的Types表):

类型:Id,类型 属性:ID,标题,TypeId Project_Attributes:Project_Id,AttributeId(用于多对多的桥表) 项目:ID,标题,...

实际上一幅价值一千个单词的图片,即使这段代码是在很短的时间内编写的(因此经过一番思考后也需要修改)会给出更多的想法。这是代码优先模型,因此您可以运行并让其为您创建表:

string defaultConString = 
@"server=.\SQLExpress;Database=SampleDb;Trusted_Connection=yes;";

void Main()
{
    CreateData();
    // check db state
    ListData();
    // Done with sample database. Delete.
    // new SampleContext(defaultConString).Database.Delete();
}

private void CreateData()
{
    var db = new SampleContext(defaultConString);
    if (db.Database.CreateIfNotExists())
    {

        // Create some types
        var tHW = new Type { Name = "Hardware" };
        var tSW = new Type { Name = "Software" };
        var tFW = new Type { Name = "Firmware" };
        db.Types.AddRange(new Type[] {tHW,tSW,tFW});
        db.SaveChanges();

        // create some Attributes using types above
        var a1 = new Attribute
        {
            Name = "Macbook Pro",
            Type = tHW,
            AttrProperties = new List<AttrProperty> {
                new AttrProperty{ Description=@"15"" retina" },
                new AttrProperty{ Description=@"i9-8950HK" },
                new AttrProperty{ Description=@"32Gb DDR4 RAM" },
                new AttrProperty{ Description=@"512Gb SSD" },
                new AttrProperty{ Description=@"AMD Radeon Pro 555" },
                new AttrProperty{ Description=@"OSX Mojave 10.14" },
                }
        };
        var a2 = new Attribute
        {
            Name = "iMac",
            Type = tHW,
            AttrProperties = new List<AttrProperty> {
                new AttrProperty{ Description=@"27"" retina 5K" },
                new AttrProperty{ Description=@"i5 3.4Ghz" },
                new AttrProperty{ Description=@"40Gb DDR4 RAM" },
                new AttrProperty{ Description=@"1Tb Fusion" },
                new AttrProperty{ Description=@"AMD Radeon Pro 570" },
                new AttrProperty{ Description=@"OSX Mojave 10.14" },
                }
        };
        var a3 = new Attribute
        {
            Name = "PC",
            Type = tHW,
            AttrProperties = new List<AttrProperty> {
                new AttrProperty{ Description=@"AMD Ryzen Threadripper 1950x" },
                new AttrProperty{ Description=@"64Gb RAM" },
                new AttrProperty{ Description=@"1 Tb 7400 RPM" },
                new AttrProperty{ Description=@"512Gb M2 mSATA" },
                new AttrProperty{ Description=@"AMD Radeon Pro 570" },
                new AttrProperty{ Description=@"Linux-Debian 9.5" },
                }
        };

        var a4 = new Attribute
        {
            Name = "Database",
            Type = tSW,
            AttrProperties = new List<AttrProperty> {
                new AttrProperty{ Description=@"postgreSQL" },
                new AttrProperty{ Description=@"11 (beta)" },
                }
        };

        var a5 = new Attribute
        {
            Name = "SomeROM",
            Type = tFW,
            AttrProperties = new List<AttrProperty> {
                new AttrProperty{ Description=@"SomeROM update" },
                new AttrProperty{ Description=@"Some version" },
                }
        };

        db.Attributes.AddRange(new Attribute[] {a1,a2,a3,a4,a5});

        // Some projects using those

        var p1 = new Project
        {
            Name = "P1",
            StartDate = new DateTime(2018, 1, 1),
            Attributes = new List<Attribute>() { a1, a2, a4 }
        };
        var p2 = new Project
        {
            Name = "P2",
            StartDate = new DateTime(2018, 1, 1),
            Attributes = new List<Attribute>() { a1, a3, a5 }
        };
        var p3 = new Project
        {
            Name = "P3",
            StartDate = new DateTime(2018, 1, 1),
            Attributes = new List<Attribute>() { a2, a3, a4, a5 }
        };

        db.Projects.AddRange(new Project[] { p1,p2,p3 });
        db.SaveChanges();
    }
}

private void ListData()
{
    var db = new SampleContext(defaultConString);
//  db.Database.Log =Console.Write;
    foreach (var p in db.Projects.Include("Attributes").ToList())
    {
        Console.WriteLine($"Project {p.Name}, started on {p.StartDate}. Has Attributes:");
        foreach (var a in p.Attributes)
        {
            Console.WriteLine($"\t{a.Name} [{a.Type.Name}] ({string.Join(",",a.AttrProperties.Select(ap => ap.Description))})");
        }
    }
}

public class Type
{
    public int TypeId { get; set; }
    public string Name { get; set; }

    public virtual List<Attribute> Attributes { get; set; }
    public Type()
    {
        Attributes = new List<Attribute>();
    }
}

public class Attribute
{
    public int AttributeId { get; set; }
    public string Name { get; set; }
    public int TypeId { get; set; }
    public virtual Type Type { get; set; }
    public virtual List<Project> Projects { get; set; }
    public virtual List<AttrProperty> AttrProperties { get; set; }
    public Attribute()
    {
        Projects = new List<Project>();
    }
}

public class AttrProperty
{ 
    public int AttrPropertyId { get; set; }
    public string Description { get; set; }
    public virtual Attribute Attribute {get;set;}
}

public class Project
{
    public int ProjectId { get; set; }
    public string Name { get; set; }
    public DateTime StartDate { get; set; }
    public virtual List<Attribute> Attributes {get;set;}

    public Project()
    {
        Attributes = new List<Attribute>();
    }
}


public class SampleContext : DbContext
{
    public SampleContext(string connectionString) : base(connectionString) { }
    public DbSet<Type> Types { get; set; }
    public DbSet<Attribute> Attributes { get; set; }
    public DbSet<Project> Projects { get; set; }
}

如果这不是一个多用户的大项目,请查看LiteDB。那可能正是您要寻找的东西,即使不是几分钟,也可以在数小时内学会。