Структура базы данных / структура нормализации должна содержать AND, OR, необязательные элементы и их отношения - PullRequest
7 голосов
/ 23 декабря 2011

Я хочу сохранить сведения о курсах колледжа в базе данных (MySql), но я не уверен, как поддерживать связь между модулями и выбранными вариантами.

В принципе, курс может иметь обязательный раздел, группуиз дополнительных модулей, раздел опций и внутри каждого из них могут быть варианты выбора, которые содержат AND или OR между модулями.


Простой пример :
Курс на 60 кредитов имеет несколькообязательные модули, которые составляют 40 кредитов.Это оставляет 20 кредитов для выбора из группы дополнительных модулей.(Сами модули могут содержать различное количество кредитов).Эффективно;('Mandatory module 1' AND 'Mandatory module 2'... AND'Mandatory module N') AND (40 credits from 'optional modules'),

И & ИЛИ :
Когда я говорю «модули выше», это может быть один модуль или «Модуль x ИЛИ модуль Y», т.е. в обязательном порядке.раздел.(эти модули, очевидно, должны иметь одинаковый вес кредита).Или в дополнительном разделе могут быть отдельные модули, или даже один из вариантов может быть что-то вроде "module x AND module y".

Опции :
Учащиеся, возможно, должны взять обязательные модулиплюс один из n параметров, которые могут содержать или не содержать AND, OR и обязательные и необязательные разделы;т. е. «Опция» имеет все атрибуты общего выбора модулей курса.Раздел «Параметры» будет «И» или «И» с другими разделами, такими как обязательный или необязательный;т.е. обязательные модули «плюс один из следующих вариантов».По сути, раздел параметров просто 'Option 1' OR 'Option 2'... OR 'Option N'.


Проблема заключается в том, как сохранить все отношения И и ИЛИ, когда операндом может быть другая операция И / ИЛИ или отдельный модуль, и отслеживать количество кредитов, разрешенных для каждого выбора.;например, «20 кредитов из следующего:» (группа дополнительных модулей).

Ответы [ 5 ]

3 голосов
/ 23 декабря 2011

Очень простой, первый подход будет использовать только 4 таблицы:

TABLE Course 
( CourseId 
, Title 
, TotalCredits 
, ... other stuff
, PRIMARY KEY (CourseId)
) ;

TABLE Module 
( ModuleId 
, Description 
, Hours
, Credits
, ... other stuff
, PRIMARY KEY (ModuleId)
) ;

и комбинации, разрешенные через эти 2:

TABLE Course_Module 
( CourseID                 --- for this course
, ModuleID                 --- this module is allowed (optional or mandatory)
, PRIMARY KEY (CourseID, ModuleId)
, FOREIGN KEY (CourseId) 
    REFERENCES Course (CourseId)
, FOREIGN KEY (ModuleId)
    REFERENCES Module (ModuleId)
) ;

TABLE Course_MandatoryModule 
( CourseID                  --- for this course
, ModuleID                  --- this module is mandatory
, PRIMARY KEY (CourseID, ModuleId)
, FOREIGN KEY (CourseID, ModuleId)
    REFERENCES Course_Module (CourseID, ModuleId)
) ;

Теперь, если допустимые комбинации модулей и курсов более сложны, как следует из вашего описания, вместо таблиц Course_Module и Course_MandatoryModule вы можете определить сложную иерархическую модель:

Курсы:

TABLE Course                        --- same as previous model
( CourseId 
, Title 
, TotalCredits 
, ... other stuff
, PRIMARY KEY (CourseId)
) ;

Модули и группы (модули):

TABLE ModuleEntity                  --- the supertype for both
( ModuleEntityId                    --- modules and group of modules
, PRIMARY KEY (ModuleEntityId)
) ;

TABLE Module                        --- subtype
( ModuleId 
, Description 
, Hours
, Credits
, ... other stuff
, PRIMARY KEY (ModuleId)
, FOREIGN KEY (ModuleId) 
    REFERENCES ModuleEntity (ModuleEntityId)
) ;

TABLE ModuleGroup                  --- group of modules
( ModuleGroupId                    --- subtype of the supertype (entity)
, GroupDescription        
, PRIMARY KEY (ModuleGroupId)
, FOREIGN KEY (ModuleGroupId) 
    REFERENCES ModuleEntity (ModuleEntityId)
) ;

и связь (модуль принадлежит группе):

TABLE Module_in_Group  
( ModuleEntityId               --- this module or group
, ModuleGroupId                --- is in this group
, PRIMARY KEY (ModuleEntityId, ModuleGroupID)
, FOREIGN KEY (ModuleEntityId)
    REFERENCES ModuleEntity (ModuleEntityId)
, FOREIGN KEY (ModuleGroupId)
    REFERENCES ModuleGroup (ModuleGroupId)
) ;

и (наконец) курс может иметь группу модулей:

TABLE Course_ModuleGroup
( CourseId                 --- for this course
, ModuleGroupId            --- this module group is allowed
, PRIMARY KEY (CourseID, ModuleGroupId)
, FOREIGN KEY (CourseId) 
    REFERENCES Course (CourseId)
, FOREIGN KEY (ModuleGroupId)
    REFERENCES ModuleGroup (ModuleGroupId)
) ;
1 голос
/ 17 января 2012

Конструкция довольно проста, вам просто нужна рекурсивная «групповая» таблица с ограничениями.

Course
- ID
- Title
- Credits

Course_Group
- CourseID
- GroupID

Group
- ID
- GroupID
- Description
- AtLeastNSelections
- AtLeastNCredits

Group_Module
- GroupID
- ModuleID

Module
- ID
- Title
- Credits

Пример структуры:

Course: 1, "Math Major", 60
Group: 1, NULL, "Core Modules", 2, 40
Course_Group: 1, 1
    Group: 2, 1, "Required (5) Core Modules", 5, 25
    Course_Group: 1, 1
    Group_Module: (1, 1), (1, 2), (1, 3), (1, 4), (1, 5)
        Module: 1, "Calculus I", 5
        Module: 2, "Calculus II", 5
        Module: 3, "Calculus III", 5
        Module: 4, "Stats I", 5
        Module: 5, "Stats II", 5
    Group: 3, 1, "Required (3) Of (N) Modules", 3, 15
    Course_Group: 1, 3
    Group_Module: (3, 6), (3, 7), (3, 8), (3, 9), (3, 10)
        Module: 6, "Number Theory", 5
        Module: 7, "Bridge Adv. Math", 5
        Module: 8, "Calculus IV", 5
        Module: 9, "Stats III", 5
        Module: 10, "Finite Math", 5
Group: 4, NULL, "Secondary Modules", 1, 20
Course_Group: 1, 4
    Group: 5, 4, "Comp. Sci.", 2, 0
    Course_Group: 1, 5
    Group_Module: (5, 11), (5, 12), (5, 13), (5, 14), (5, 15), (5, 16)
        Module: 11, "Math in Hardware", 4
        Module: 12, "Math in Software", 4
        Module: 13, "Programming 101", 4
        Module: 14, "Algorithms 101", 4
        Module: 15, "Programming I", 5
        Module: 16, "Programming II", 5
    Group: 6, 4, "Physics", 0, 8
    Course_Group: 1, 6
    Group_Module: (6, 17), (6, 18), (6, 19), (6, 20)
        Module: 17, "Physics Mechanics", 4
        Module: 18, "Physics Thermodynamics", 4
        Module: 19, "Physics Magnetism", 5
        Module: 20, "Physics Theoretical", 5
    Group: 7, 4, "Gen. Ed.", 0, 0
    Course_Group: 1, 7
    Group_Module: (7, 21), (7, 22), (7, 23), (7, 24)
        Module: 21, "Business Writing", 3
        Module: 22, "Ethics", 3
        Module: 23, "Aesthetics", 3
        Module: 24, "Graphic Design", 3

Быстрый просмотр... курс "Math Major" состоит из двух групп: "Основные модули" и "Вторичные модули".«Основные модули» требуют, по крайней мере, 2 детей и, по крайней мере, 40 кредитов.Для «Вторичных модулей» требуется по крайней мере 1 дочерний элемент и, по крайней мере, 20 кредитов.

Вы можете видеть, что ограничения групп в «Базовых модулях» являются более строгими, чем ограничения групп в «Вторичных модулях».

Вывести приведенную выше примерную структуру можно примерно так:

SELECT c.Title, g.Description, m.Title FROM Course c
 INNER JOIN Course_Group cg ON c.ID = cg.CourseID
 INNER JOIN Group g ON cg.GroupID = g.ID
 INNER JOIN Group_Module gm ON g.ID = gm.GroupID
 INNER JOIN Module m ON gm.ModuleID = m.ID
WHERE c.ID = 1
ORDER BY g.GroupID, g.ID, m.Title  

Так что, если у вас есть курс и модули, вы можете получить все группы для курса из таблицы Course_Group и получить какиегруппа, к которой принадлежат модули, из таблицы Group_Module.Когда у вас есть модули в их группах, вы можете проверить ограничения группы AtLeastNSelections AND AtLeastNCredits, пройдя по цепочке происхождения Group.GroupID, пока не доберетесь до Group.GroupID = NULL.

1 голос
/ 23 декабря 2011

Вы, вероятно, можете сделать что-то вроде этого:

TABLE course_definition (
    ID int,
    num_mandatory_sections int,
    mandatory_hours int,
    num_optional_modules int,
    optional_hours int,
);

TABLE modules (
    ID int,
    Description varchar(max),
    hours int,
    ....
);

TABLE course (
    Course_ID int FOREIGN KEY (course_definition.id),
    module_id int FOREIGN KEY (modules.id)
);

TABLE course_module_relationship (
     Course_ID int FOREIGN KEY (course_definition.id),
     module_ID int foreign key (modules.id),
     Requirement_flag ENUM ("MANDATORY", "OPTIONAL")
);

TABLE Student_to_course (
     Student_ID int,
     Course_ID int foreign key (course_definition.id)
);

TABLE Student_to_module (
     Student_ID int,
     Module_ID int FOREIGN KEY (module.id)
);

Если вам действительно нужно иметь возможность создавать групповые модули, то есть один модуль, созданный из нескольких других модулей, тогда таблица module должна иметьполе флага:

group_module boolean

и следует добавить следующую таблицу:

TABLE module_groupings (
    group_module_ID int foreign key (module.id)
    dependant_module_id int foreign key (module.id)
);

Это скорее псевдокод, но вы поняли идею.Таблицы course и course_module_relationship не будут иметь ключей и будут хранить ваши отношения, так как их может быть много ко многим, насколько я понимаю проблему.Таким образом, в основном код, который будет читать, обрабатывает выборки, чтобы проверить, соответствует ли это критериям course_definition.

. Если обязательный раздел к курсу является отношением 1 к 1, вы можете отделитьваш обязательный раздел в отдельной таблице, но вам придется анализировать свои данные более тщательно.

1 голос
/ 23 декабря 2011

Здесь вы можете создать рекурсивную структуру таблицы, в которой параметры ссылаются на родительские параметры.

  • Затем можно определить «основные» параметры, запросив эту таблицу для всех параметров с «нулевыми» родителями.

  • Отношения «и / или» могут быть реализованы отдельной таблицей «набор опций», где первичным ключом является «опция».Таблицы наборов опций с нулевыми собственными ссылками являются «корневой» точкой для определения опций курса.С этого момента вы выберете набор опций записей с parent = root.Это будет первый «уровень» опций.Некоторые будут обязательными, некоторые нет.Чтобы выразить это, вам нужно будет иметь логический атрибут в таблице наборов опций в качестве флага.Таким образом, каждый набор опций определяется в терминах меньших наборов опций.Конечно, в конечном итоге, как только вы доберетесь до сути, ваш набор опций определит реальный класс в какой-то момент.

Я бы предположил, что это может быть гораздо более эффективно смоделировано в JSON или XML, поскольку эти структуры данных поддерживают иерархии гораздо более выразительным образом.

0 голосов
/ 16 января 2012

Система качества производства, использующая и / или (например, ваша система), которую вы можете просмотреть бесплатно, - это Entlib 5.0 Security block. http://entlib.codeplex.com/

Каждое правило извлекается name , чтобы получить полное выражение . команда шаблонов и практики создала свой собственный короткий DSL для выражение, чтобы избежать усложнения структуры xml / db.

Это лабораторное упражнение ex02 app.config. Чтобы хранить правила внутри базы данных, вам необходимо реализовать пользовательский AuthorizationRuleProvider.

R: = rolename; U: = имя пользователя

  <securityConfiguration defaultAuthorizationInstance="RuleProvider"
defaultSecurityCacheInstance="">
<authorizationProviders>
  <add type="Microsoft.Practices.EnterpriseLibrary.Security.AuthorizationRuleProvider, Microsoft.Practices.EnterpriseLibrary.Security"
    name="RuleProvider">
    <rules>
      <add expression="R:Employee OR R:Developer OR R:Manager" name="Raise Bug" />
      <add expression="R:Manager" name="Assign Bug" />
      <add expression="R:Developer OR R:Manager" name="Resolve Bug" />
    </rules>
  </add>
</authorizationProviders>

Девелопмент

    public static AssignBug Create()
    {
        // TODO: Check Authorization
        if (!SecurityHelper.Authorized(AuthRule.Assign))
        {
            throw new SecurityException();
        }

        return new AssignBug();
    }

Хотя это и не немедленный ответ, я думаю, что это хороший пример того, как реализовать системы, основанные на выражениях правил.

...