MySQL INSERT с использованием только SQL - PullRequest
1 голос
/ 30 января 2011

Возможно ли использовать только SQL и MySQL, чтобы получить "OUTPUT" ниже?

ОБРАЗЕЦ ДАННЫХ: Чтобы лучше проработать пример, предположим, что я пытаюсь загрузить файл, содержащий имя сотрудника, должности, которые они занимали в прошлом, и историю их должностей, разделенных вкладкой.

Файл:

EmployeeName<tab>OfficeHistory<tab>JobLevelHistory
John Smith<tab>501<tab>Engineer
John Smith<tab>601<tab>Senior Engineer
John Smith<tab>701<tab>Manager
Alex Button<tab>601<tab>Senior Assistant
Alex Button<tab>454<tab>Manager

ПРИМЕЧАНИЕ: База данных с одной таблицей полностью нормализована (насколько может быть одна таблица) - и, например, в случае с «Джоном Смитом» есть только один Джон Смит; Это означает, что нет дубликатов, которые могли бы привести к конфликтам в ссылочной целостности.

Схема базы данных MyOffice имеет следующие таблицы:

Employee (nId, name)
Office (nId, number)
JobTitle (nId, titleName)
Employee2Office (nEmpID, nOfficeId)
Employee2JobTitle (nEmpId, nJobTitleID)

ВЫХОД: Так и в этом случае. таблицы должны выглядеть так:

Employee
1 John Smith
2 Alex Button

Office
1 501
2 601
3 701
4 454

JobTitle
1 Engineer
2 Senior Engineer
3 Manager
4 Senior Assistant

Employee2Office
1 1
1 2
1 3
2 2
2 4

Employee2JobTitle
1 1
1 2
1 3
2 4
2 3

Вот MySQL DDL для создания базы данных и таблиц:

create database MyOffice2;

use MyOffice2;

CREATE TABLE Employee (
      id MEDIUMINT NOT NULL AUTO_INCREMENT,
      name CHAR(50) NOT NULL,
      PRIMARY KEY (id)
    ) ENGINE=InnoDB;

CREATE TABLE Office (
  id MEDIUMINT NOT NULL AUTO_INCREMENT,
  office_number INT NOT NULL,
  PRIMARY KEY (id)
) ENGINE=InnoDB;

CREATE TABLE JobTitle (
  id MEDIUMINT NOT NULL AUTO_INCREMENT,
  title CHAR(30) NOT NULL,
  PRIMARY KEY (id)
) ENGINE=InnoDB;

CREATE TABLE Employee2JobTitle (
  employee_id MEDIUMINT NOT NULL,
  job_title_id MEDIUMINT NOT NULL,
  FOREIGN KEY (employee_id) REFERENCES Employee(id),
  FOREIGN KEY (job_title_id) REFERENCES JobTitle(id),
  PRIMARY KEY (employee_id, job_title_id)
) ENGINE=InnoDB;

CREATE TABLE Employee2Office (
  employee_id MEDIUMINT NOT NULL,
  office_id MEDIUMINT NOT NULL,
  FOREIGN KEY (employee_id) REFERENCES Employee(id),
  FOREIGN KEY (office_id) REFERENCES Office(id),
  PRIMARY KEY (employee_id, office_id)
) ENGINE=InnoDB;

Ответы [ 3 ]

2 голосов
/ 30 января 2011

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

create table TmpEmp (
EmployeeName char(50) not null,
OfficeHistory int null,
JobLevelHistory char(30) null);

Создайте триггер для этой таблицы

delimiter |
CREATE TRIGGER tg_TmpEmp BEFORE INSERT ON TmpEmp
FOR EACH ROW
BEGIN
IF not exists (select * from Employee where Name = NEW.EmployeeName) THEN
    INSERT INTO Employee(name)
        select NEW.EmployeeName;
END IF;
IF not exists (select * from Office where office_number = NEW.OfficeHistory) THEN
    INSERT INTO Office(office_number)
        select NEW.OfficeHistory;
END IF;
IF not exists (select * from JobTitle where title = NEW.JobLevelHistory) THEN
    INSERT INTO JobTitle(title)
        select NEW.JobLevelHistory;
END IF;
INSERT INTO Employee2JobTitle(employee_id,job_title_id)
    select E.id, T.id
    from Employee E
    inner join JobTitle T on T.title = NEW.JobLevelHistory
    where E.Name = NEW.EmployeeName
        AND not exists (select *
            from Employee2JobTitle J
            where J.employee_id = E.id and J.job_title_id = T.id);
INSERT INTO Employee2Office(employee_id,office_id)
    select E.id, O.id
    from Employee E
    inner join Office O on O.office_number = NEW.OfficeHistory
    where E.Name = NEW.EmployeeName
        AND not exists (select *
            from Employee2Office J
            where J.employee_id = E.id and J.office_id = O.id);
END; |
delimiter ;

Примечание : Преимущество этого триггера и таблицы в том, что она работает независимо от того, используете ли вы LOAD-FILE или просто вставки.Триггер срабатывает и добавляет данные в нужное место.

Проверьте его

insert tmpEmp(EmployeeName,OfficeHistory,JobLevelHistory)
select 'John Smith',501,'Engineer' union all
select 'John Smith',601,'Senior Engineer' union all
select 'John Smith',701,'Manager' union all
select 'Alex Button',601,'Senior Assistant' union all
select 'Alex Button',454,'Manager';

truncate table tmpEmp;
1 голос
/ 30 января 2011

Возможно, вы могли бы заставить его работать, используя синтаксис MySQL LOAD DATA INFILE .

В соответствии со спецификацией вы можете использовать его следующим образом:

LOAD DATA INFILE 'data.txt' INTO TABLE db2.my_table;

и такими настройками:

FIELDS TERMINATED BY '\t' ENCLOSED BY '' ESCAPED BY '\\'
LINES TERMINATED BY '\n' STARTING BY ''

РЕДАКТИРОВАТЬ.

1) Load the file into a temp file, let's call it table temp (left out in this example)
2) Insert basic data into right tables
  INSERT INTO Employee (name)   
  Select distinct name from temp;

  INSERT INTO Office (office_number)
  Select DISTINCT office from temp;

  INSERT INTO JobTitle (title)
  Select DISTINCT job_level from temp;

3) Create mapping tables by using joins, like:

  INSERT INTO Employee2Office (employee_id, office_id)
  select Employee.id, office.id from temp
  INNER JOIN Employee ON temp.name = Employee.name
  INNER JOIN Office ON temp.office = Office.office_number

  Follow the same approach for the other mapping table. 
0 голосов
/ 30 января 2011

Что касается предложения временной таблицы, я просто не понимаю как временная таблица будет отличаться от "реальной" таблицы; то есть я знаю, что такое временная таблица, просто не понимаю, как это сделать Разница в процессе загрузки.

Временная таблица позволит вам загрузить данные в одну плоскую таблицу. Например, вы можете реализовать следующий процесс в SQL:

  1. Отключить проверку внешнего ключа
  2. Создайте временную таблицу для хранения данных в плоском файле как
  3. Загрузка данных плоского файла во временную таблицу
  4. используйте INSERT INTO ... SELECT FROM для загрузки данных в ваши основные таблицы (Employee, JobTitle, Office - так 3 запроса)
  5. Используйте запрос, чтобы выбрать два столбца с автоинкрементом в основной таблице на основе соотношения значений в основной и временной таблицах, и вставьте их в таблицу объединения (вы сделаете это дважды, один раз для каждой таблицы объединения )
  6. Включить проверку внешнего ключа

Это то, что я имел ввиду под сценарием. Нет никакого способа, которым MySQL мог бы волшебным образом отобразить отношения из плоских данных. Вы должны сделать это самостоятельно. Вы можете написать его на SQL, используя шаги, описанные выше, но кажется, что вместо этого будет проще использовать знакомый вам язык сценариев, который позволяет избежать всевозможных проблем с разрешениями / доступом при использовании LOAD DATA.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...