Предотвратить повторяющиеся записи при вставке через другие таблицы - PullRequest
0 голосов
/ 31 января 2020

Мне нужно извлечь некоторые значения столбцов из T2 и вставить их в T3, выполнив цикл T1. И, конечно же, я должен избегать повторяющихся записей в T3.

Мои таблицы:

My tables

CREATE TABLE T1 (
    Id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
    PRIMARY KEY (Id)
);

CREATE TABLE T2 (
    Id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
    FK_T1 BIGINT(20) UNSIGNED NOT NULL,
    Desc VARCHAR(10) NOT NULL,
    PRIMARY KEY (Id),
    UNIQUE KEY FK_T1 (FK_T1),
    CONSTRAINT FK_T2_T1 FOREIGN KEY (FK_T1) REFERENCES T1 (Id)
);

CREATE TABLE T3 (
    Id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
    FK_T1 BIGINT(20) UNSIGNED NOT NULL,
    T2Desc VARCHAR(10) NOT NULL,
    PRIMARY KEY (Id),
    UNIQUE KEY FK_T1 (FK_T1),
    CONSTRAINT FK_T3_T1 FOREIGN KEY (FK_T1) REFERENCES T1 (Id)
);

Данные:

T1
+----+
| Id |
+----+
| 11 |
| 12 |
+----+

T2
+----+-------+--------+
| Id | FK_T1 | Desc   |
+----+-------+--------+
| 21 | 11    | desc 1 |
| 22 | 12    | desc 2 |
+----+-------+--------+

T3
+----+-------+--------+
| Id | FK_T1 | T2Desc |
+----+-------+--------+
| xx | 11    | desc 1 |
+----+-------+--------+

Я ожидаю, что новая строка будет добавлена ​​в T3, когда я выполню следующий запрос, но это даст Duplicate entry '11' for key 'FK_T1' ошибку курса:

-- expected new row to be added => | xx | 12 | desc 2 |

INSERT INTO T3(FK_T1, T2Desc)  (
    SELECT t2.FK_T1, t2.Desc
    FROM T2 t2
    INNER JOIN T1 t1 ON t1.Id = t2.FK_T1
);

Как я могу заставить этот запрос работать с явным расширением? Может быть, используя LEFT JOIN, чтобы я даже мог сначала отфильтровать T1 чем-то вроде WHERE T1.Id > 10?

Ответы [ 3 ]

2 голосов
/ 31 января 2020

Тест

INSERT IGNORE INTO T3 (FK_T1, T2Desc)
SELECT T2.FK_T1, T2.`Desc`
FROM T1
JOIN T2 ON T1.Id = T2.FK_T1;

скрипка

PS. Плохо использовать зарезервированное слово Desc в качестве имени поля.

1 голос
/ 02 февраля 2020

Вы также можете использовать этот запрос без INGORE. При этом выбираются только строки, которых нет в table3, и выполняется вставка.

INSERT INTO T3 (FK_T1, T2Desc)
SELECT T2.FK_T1, t2.Desc
FROM T2 T2 
JOIN T1 T1 ON T1.Id = T2.FK_T1
LEFT JOIN T3 T3 ON T2.FK_t1 = T3.FK_T1 
WHERE T3.FK_T1 IS NULL;

SAMPLE см. fiddle

CREATE TABLE T1 (
    Id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
    PRIMARY KEY (Id)
);
CREATE TABLE T2 (
    Id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
    FK_T1 BIGINT(20) UNSIGNED NOT NULL,
    `Desc` VARCHAR(10) NOT NULL,
    PRIMARY KEY (Id),
    UNIQUE KEY FK_T1 (FK_T1),
    CONSTRAINT FK_T2_T1 FOREIGN KEY (FK_T1) REFERENCES T1 (Id)
);
CREATE TABLE T3 (
    Id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
    FK_T1 BIGINT(20) UNSIGNED NOT NULL,
    T2Desc VARCHAR(10) NOT NULL,
    PRIMARY KEY (Id),
    UNIQUE KEY FK_T1 (FK_T1),
    CONSTRAINT FK_T3_T1 FOREIGN KEY (FK_T1) REFERENCES T1 (Id)
);

add Строки

INSERT INTO T1 VALUES (11),(12);
INSERT INTO T2 VALUES (21, 11, 'desc 1'), (22, 12, 'desc 2');
INSERT INTO T3 VALUES (31, 11, 'desc 1');

Обновление T3

mysql> INSERT INTO T3 (FK_T1, T2Desc)
    -> SELECT T2.FK_T1, T2.Desc
    -> FROM T2 T2
    -> JOIN T1 T1 ON T1.Id = T2.FK_T1
    -> LEFT JOIN T3 T3 ON T2.FK_t1 = T3.FK_T1
    -> WHERE T3.FK_T1 IS NULL;
Query OK, 1 row affected (0.01 sec)
Records: 1  Duplicates: 0  Warnings: 0

см. Результат

mysql> SELECT * FROM T3;
+----+-------+--------+
| Id | FK_T1 | T2Desc |
+----+-------+--------+
| 31 |    11 | desc 1 |
| 32 |    12 | desc 2 |
+----+-------+--------+
2 rows in set (0.00 sec)

mysql>

вставить новую строку и проверить

mysql> INSERT INTO T1 VALUES (33),(34);
Query OK, 2 rows affected (0.00 sec)
Records: 2  Duplicates: 0  Warnings: 0

mysql> INSERT INTO T2 VALUES (41, 33, 'desc 33'), (51, 34, 'desc 34');
Query OK, 2 rows affected (0.00 sec)
Records: 2  Duplicates: 0  Warnings: 0

mysql>


mysql> INSERT INTO T3 (FK_T1, T2Desc)
    -> SELECT T2.FK_T1, T2.Desc
    -> FROM T2 T2
    -> JOIN T1 T1 ON T1.Id = T2.FK_T1
    -> LEFT JOIN T3 T3 ON T2.FK_t1 = T3.FK_T1
    -> WHERE T3.FK_T1 IS NULL;
Query OK, 2 rows affected (0.00 sec)
Records: 2  Duplicates: 0  Warnings: 0

mysql> SELECT * FROM T3;
+----+-------+---------+
| Id | FK_T1 | T2Desc  |
+----+-------+---------+
| 31 |    11 | desc 1  |
| 32 |    12 | desc 2  |
| 33 |    33 | desc 33 |
| 34 |    34 | desc 34 |
+----+-------+---------+
4 rows in set (0.00 sec)

повторить запрос без таблиц

mysql> INSERT INTO T3 (FK_T1, T2Desc)
    -> SELECT T2.FK_T1, T2.Desc
    -> FROM T2 T2
    -> JOIN T1 T1 ON T1.Id = T2.FK_T1
    -> LEFT JOIN T3 T3 ON T2.FK_t1 = T3.FK_T1
    -> WHERE T3.FK_T1 IS NULL;
Query OK, 0 rows affected (0.00 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql>
0 голосов
/ 02 февраля 2020

Использование INSERT IGNORE может быть дорогостоящим, особенно если в таблице много строк или данные, которые вы хотите вставить, содержат много дубликатов.

Так почему бы не сделать вещи простыми и фильтровать дубликаты уже в вашем утверждении select?

INSERT INTO T3 (FK_T1, T2Desc)
SELECT t2.FK_T1, t2.Desc1 FROM T2 t2 JOIN T3 t3 
  ON t2.FK_t1 != t3.FK_T1 
INNER JOIN T1 t1 ON t1.Id = t2.FK_T1
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...