内部连接到 temp table 并插入到 table in MySql

Inner joining on to temp table and insert to table in MySql

我有一个字符串列表。他们每个人都有类别,由'/'分隔。

例如:

animals/domestic/dog

animals/domestic/cat

我想对这些类别执行的操作是插入 MySql 个类别 table。 table 有 4 列: id(整数自动递增),category_name(nvarchar),parent_id(整数),is_active(位)

插入这些的逻辑如下:

主要类别(动物)的 parent_id 应为 0。

子类别的父类别 ID 为 parent_id。

不能有两个具有相同类别名称的活动类别。

我尝试实现了以下逻辑:

  1. 获取不同的字符串列表。

  2. 从中得到一个不同的主要类别列表。

  3. 将不同的主要类别插入父 ID 为 0 的类别 table。

  4. 将每个类别成对组织并获得不同的对:

(动物,家养)

(家养,狗)

(国产,猫)

  1. 获取每个父类别的匹配 ID 并插入子类别的 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;           

问题: 在查询为 运行 之后,我希望在类别 table 中有 4 个条目。

但是我只得到2个

我可以看到临时 table 在执行最后一个内部联接之前有正确的条目。 我似乎无法弄清楚为什么类别 table 没有其他两行。

非常感谢任何正确方向的指导。

更新 #1 假设规格说 'There cannot be two active categories with the same category name that had the same parent IDs'。 例如,如果有两个字符串 (animals/domestic/cat)、(animals/outdoor/cat),则应该有两个 ID 为国内和室外的猫条目,如 parent_id's.

在 MySQL8 中,您可以使用单个查询来完成此操作:

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;

Here 是一个 db<>fiddle.

不幸的是,这在早期版本中要痛苦得多。

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        

db<>fiddle here