Нормализация - это удаление избыточности и логических ошибок из базы данных. Избыточность часто приводит к логическим ошибкам, хотя в большинстве случаев эти ошибки являются результатом подхода без проектирования или из-за прямого перехода к физическому проектированию.
Вот пример одного возможного логического проектирования.
-- Job named JOB_NAME exists
--
job {JOB_NAME}
PK {JOB_NAME}
-- Action named ACTION_NAME exists.
--
action {ACTION_NAME}
PK {ACTION_NAME}
-- Job JOB_NAME involves action ACTION_NAME.
--
job_action {JOB_NAME, ACTION_NAME}
PK {JOB_NAME, ACTION_NAME}
FK1 {JOB_NAME} REFERENCES job {JOB_NAME}
FK2 {ACTION_NAME} REFERENCES action {ACTION_NAME}
-- Action ACTION_NAME has associated step number STEP_NO in job JOB_NAME.
--
job_step {JOB_NAME, STEP_NO, ACTION_NAME}
PK {JOB_NAME, STEP_NO}
FK1 {JOB_NAME, ACTION_NAME} REFERENCES job_action {JOB_NAME, ACTION_NAME}
С этого момента вы можете начать думать о физическом дизайне: размеры индексов столбцов и т. Д. c. И решить добавить числовое значение IDs
для использования в PKs
. В зависимости от размера БД, СУБД и используемого оборудования, вы можете оставить все как есть. Я сознательно избегая добавления IDs
на этом этапе.
Примером является PostgreSQL (если он установлен) - его легко настроить для MySQL. Для MySQL используйте varchar(25)
вместо TEXT
, и пример должен работать нормально (не проверено).
CREATE TABLE job (
JOB_NAME TEXT NOT NULL
, CONSTRAINT pk_job PRIMARY KEY (JOB_NAME)
);
CREATE TABLE action_ (
ACTION_NAME TEXT NOT NULL
, CONSTRAINT pk_action PRIMARY KEY (ACTION_NAME)
);
CREATE TABLE job_action (
JOB_NAME TEXT NOT NULL
, ACTION_NAME TEXT NOT NULL
, CONSTRAINT pk_job_action PRIMARY KEY (JOB_NAME, ACTION_NAME)
, CONSTRAINT fk1_job_action
FOREIGN KEY (JOB_NAME) REFERENCES
job (JOB_NAME)
, CONSTRAINT fk2_job_action
FOREIGN KEY (ACTION_NAME) REFERENCES
action_ (ACTION_NAME)
);
CREATE TABLE job_step (
JOB_NAME TEXT NOT NULL
, ACTION_NAME TEXT NOT NULL
, STEP_NO BIGINT NOT NULL
, CONSTRAINT pk_job_step PRIMARY KEY (JOB_NAME, STEP_NO)
, CONSTRAINT fk1_job_step
FOREIGN KEY (JOB_NAME, ACTION_NAME) REFERENCES
job_action (JOB_NAME, ACTION_NAME)
);
Вставьте некоторые тестовые данные; обратите внимание, что номера шагов не являются последовательными, оставляя пробелы для будущих промежуточных шагов.
INSERT INTO job (JOB_NAME)
VALUES
('build')
, ('drill')
;
INSERT INTO action_ (ACTION_NAME)
VALUES
('procure wood')
, ('grab hammer')
, ('hammer')
, ('get screw')
, ('charge drill')
, ('start drilling')
;
INSERT INTO job_action (JOB_NAME, ACTION_NAME)
VALUES
('build','procure wood')
, ('build','grab hammer')
, ('build','hammer')
, ('drill','get screw')
, ('drill','charge drill')
, ('drill','start drilling')
;
INSERT INTO job_step (JOB_NAME, ACTION_NAME, STEP_NO)
VALUES
('build','procure wood', 1000000)
, ('build','grab hammer' , 2000000)
, ('build','hammer' , 3000000)
, ('drill','get screw' , 1000000)
, ('drill','charge drill' , 2000000)
, ('drill','start drilling', 3000000)
;
Запрос возвращает правильные результаты
SELECT JOB_NAME
, rank() OVER (PARTITION BY JOB_NAME ORDER BY STEP_NO ASC) AS STEP
, ACTION_NAME
FROM job_step
ORDER BY JOB_NAME ;
+----------+------+----------------+
| job_name | step | action_name |
+----------+------+----------------+
| build | 1 | procure wood |
| build | 2 | grab hammer |
| build | 3 | hammer |
| drill | 1 | get screw |
| drill | 2 | charge drill |
| drill | 3 | start drilling |
+----------+------+----------------+
И для вставки get nails
в задание на сборку.
-- first define the new action
INSERT INTO action_ (ACTION_NAME) VALUES ('get nails');
-- associate it with the build job
INSERT INTO job_action (JOB_NAME, ACTION_NAME)
VALUES ('build','get nails');
-- insert between grab hammer and hammer
INSERT INTO job_step (JOB_NAME, ACTION_NAME, STEP_NO)
VALUES ('build','get nails', 2500000) ;
А теперь запрос возвращает:
+----------+------+----------------+
| job_name | step | action_name |
+----------+------+----------------+
| build | 1 | procure wood |
| build | 2 | grab hammer |
| build | 3 | get nails |
| build | 4 | hammer |
| drill | 1 | get screw |
| drill | 2 | charge drill |
| drill | 3 | start drilling |
+----------+------+----------------+