【问题标题】:Inner joining on to temp table and insert to table in MySql内部连接到临时表并插入到 MySql 中的表
【发布时间】:2020-05-29 03:47:05
【问题描述】:

我有一个字符串列表。它们中的每一个都有由“/”分隔的类别。

例如:

动物/家养/狗

动物/家养/猫

我想要对这些类别做的是插入到 MySql 类别表中。 该表有 4 列: id (int auto increment), category_name (nvarchar), parent_id (int), is_active (bit)

插入这些的逻辑应该如下:

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

子类别的父类别的 id 为 parent_id。

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

我已经尝试实现以下逻辑:

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

  2. 从中获取主要类别的不同列表。

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

  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;           

问题: 运行查询后,我预计类别表中有 4 个条目。

但我只得到 2 个。

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

高度赞赏任何正确方向的指导。

更新 #1 假设规范说“不能有两个具有相同类别名称的活动类别具有相同的父 ID”。 例如,如果有两个字符串,即 (animals/domestic/cat)、(animals/outdoor/cat),则应该有两个 cat 条目,其父 ID 为 home 和outer。

【问题讨论】:

  • 你用的是什么版本的 MySQL?
  • @GordonLinoff 它是'5.6.46-log'

标签: mysql sql insert inner-join temp-tables


【解决方案1】:
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;
编号 |类别名称 | parent_id |活跃 -: | :------------ | --------: | :-------- 1 |动物 | 0 | 1 4 |国内| 1 | 1 7 |狗 | 4 | 1 8 |猫 | 4 | 1

db小提琴here

【讨论】:

  • 谢谢。这符合规范的要求。也很容易理解。 UNIQUE INDEX idx_name_active (category_name) 当前决定是否应复制类别名称。我在帖子中添加了更新 #1。我将如何更改上述行来实现这一目标?
  • 为了记录,我通过调整唯一索引UNIQUE INDEX idx_name_active (category_name, parent_id)设法实现了上述目标。
【解决方案2】:

在 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;

Here 是一个 dbfiddle。

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

【讨论】:

    猜你喜欢
    • 2016-01-31
    • 2018-11-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-04
    • 1970-01-01
    • 2018-06-20
    • 1970-01-01
    相关资源
    最近更新 更多