Внутреннее соединение с временной таблицей и вставка в таблицу в MySql - PullRequest
0 голосов
/ 13 февраля 2020

У меня есть список строк. У каждой из них есть категории, которые разделены символом '/'.

Например:

животные / домашние / собака

животные / домашние / кошка

Что я хочу сделать с этими категориями, это вставить в таблицу категорий MySql. Таблица имеет 4 столбца: id (int с автоматическим приращением), category_name (nvarchar), parent_id (int), is_active (бит)

Лог c вокруг их вставки должен выглядеть следующим образом:

Основные категории (животные) должны иметь parent_id = 0.

Дочерние категории будут иметь идентификатор своего родителя в качестве parent_id.

Не может быть двух активных категорий с одной и той же категорией имя.

Я пытался реализовать следующие логи c:

  1. Получить отдельный список строк.

  2. Из них получите четкий список основных категорий.

  3. Вставьте отдельные основные категории в таблицу категорий с родительским идентификатором 0.

  4. Организуйте каждую из категорий в парах и получайте отдельные пары:

(животные, домест c)

(домест c, собака)

(домест c, кошка)

Получите соответствующий идентификатор для каждой из родительских категорий и вставьте его в parent_id ребенка

SQL:

/*INSERT ALL THE FIRST PARENT CATEGORIES WITH A PARENT ID OF 0*/
            INSERT INTO categories (category_name, parent_id, is_active)
            VALUES ('animals', 0, 1);

/*INSERT ALL THE CATEGORIES IN PAIRS TO TEMP TABLE*/
            CREATE TEMPORARY TABLE tempcat(parent nvarchar(256), child nvarchar(256));
            INSERT INTO tempcat
            VALUES ('animals', 'domestic'),('domestic', 'dog'),('domestic','cat');

/*INSERT INTO THE CATEGORIES TABLE*/
            INSERT INTO categories(category_name, parent_id, is_active)
            SELECT tempcat.child, categories.id, 1            
            FROM categories
            INNER JOIN tempcat
            ON categories.category_name = tempcat.parent;
            WHERE categories.is_active = 1;

/*DISPOSE THE TEMPORARY TABLE*/
            DROP TEMPORARY TABLE tempcat;           

Проблема: после запуска запроса I Ожидайте 4 записи в таблице категорий.

Expected

Но я получаю только 2.

Actual

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

Любые указания в правильном направлении очень ценятся.

Обновление # 1 Предположим, что спецификации гласят: «Не может быть двух активных категорий с одинаковым именем категории , имеющих одинаковые родительские идентификаторы ». Например, если было две строки, такие как (животные / домашние / кошка), (животные / на открытом воздухе / кошка), должно быть две записи для кошки с идентификаторами доменных c и наружных как parent_id.

Ответы [ 2 ]

1 голос
/ 13 февраля 2020
CREATE TABLE categories (id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
                         category_name VARCHAR(64), 
                         parent_id INT UNSIGNED NOT NULL DEFAULT 0,
                         is_active CHAR(1) NULL,
                         UNIQUE INDEX idx_name_active (category_name));
CREATE TABLE source_data (path TEXT);
INSERT INTO source_data VALUES ('animals/domestic/dog'), ('animals/domestic/cat');
CREATE PROCEDURE update_categories_table()
BEGIN
DECLARE cnt INT DEFAULT 0;
INSERT IGNORE INTO categories (category_name, parent_id, is_active)
SELECT SUBSTRING_INDEX(path, '/', 1), 0, '1'
FROM source_data;
iteration: LOOP
    SELECT COUNT(*) INTO cnt
    FROM source_data
    WHERE LOCATE('/', path);
    IF NOT cnt THEN 
        LEAVE iteration;
    END IF;
    INSERT IGNORE INTO categories (category_name, parent_id, is_active)
    SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(source_data.path, '/', 2), '/', -1),
           categories.id,
           '1'
    FROM source_data, categories
    WHERE SUBSTRING_INDEX(source_data.path, '/', 1) = categories.category_name;
    UPDATE source_data
    SET path = SUBSTRING(path FROM 1 + LOCATE('/', path));
END LOOP iteration;
TRUNCATE source_data;
END
call update_categories_table;
SELECT * FROM categories;
id | category_name | parent_id | is_active
-: | :------------ | --------: | :--------
 1 | animals       |         0 | 1        
 4 | domestic      |         1 | 1        
 7 | dog           |         4 | 1        
 8 | cat           |         4 | 1        

дБ <> скрипка здесь

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

В MySQL 8 вы можете сделать это с помощью одного запроса:

with splits as (
      select 1 as n, substring_index(cats, '/', 1) as cat, cats
      from strings union all
      select 2 as n, substring_index(substring_index(cats, '/', 2), '/', -1) as cat, cats
      from strings 
      where cats like '%/%' union all
      select 3 as n, substring_index(substring_index(cats, '/', 3), '/', -1) as cat, cats 
      from strings
      where cats like '%/%/%'
     ),
     splits_n as (
      select s.*, dense_rank() over (order by n, cat) as new_id
      from splits s
     ),
     splits_np as (
      select s.*, sp.new_id as parent_id
      from splits_n s left join
           splits_n sp
           on sp.cats = s.cats and sp.n = s.n - 1
     ) 
select distinct new_id as id, cat, parent_id, 1 as is_active
from splits_np s;

Здесь - это db <> скрипка.

К сожалению, это гораздо более болезненный в более ранних версиях.

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