绝望地坚持到目前为止,直到现在我的编程快速拨号伙伴都没有能够提供帮助(大多数人不是MySQL专家):
我有不同的表,其中使用CSV文件从“导入表数据向导”自动生成列名和数据类型,并且该表还没有包含AUTO INCREMENT列。这个特殊的表由大约30.000行组成。它从一个如下所示的表开始于row = id(1):
我正在尝试使用一个'更正'表来纠正comma delimited
一列中的值。为此,我正在编写一个包含WHILE循环的存储过程,以便通过行的更正表行进行交互,并检查是否在导入的表中找到了别名。
| id | material | alias01 | alias02 | alias03 | *up to 12
1 Katoen Cotton Supima Pima
2 Polyester Polyster
3 Lyocell Lycocell Lyocel
4 Linnen Linen
5 Viscose Visose Viskose Viscoe Voscose
6 Scheerwol
7 Polyamide
8 Nylon
9 Leer Leder Lamsleder Varkensleder
10 Polyurethaan Polyurethan PU Polyuretaan
为了测试目的来测试任何类型的结果我现在只使用alias01(它需要检查alias01,然后是02等...但我会在稍后尝试解决这个问题)。
需要比较`Length'(alias_string_length = found_string_length)以确保在'wool'或'wol'中找不到由'wo'组成的字符串。
需要更正的列中的值看起来像这样(逗号不需要在那里它就是我给予的工作):
| material |
,Katoen,Elastaan,Voering,Acetaat,Polyester
,Nylon,Polyester,Elastaan
,Katoen
,Leder,in,Leder,Loopzool,Leder
,Polyester
,Polyester,Elastaan,Voering,Polyester
更新
感谢Drew的提示,我改变了程序。我添加了一个tmp表,其中包含材料和每行的唯一ID,并使用alias01迭代每个。执行9000行需要大约11秒,但0 row(s) affected,
。关于提高速度的任何提示都是最受欢迎的,但对可能存在的问题的深入了解会有所帮助。
CREATE DEFINER=`root`@`localhost` PROCEDURE `replace_materials`()
BEGIN
set @rownumber = 1;
set @totalrows = 28;
set @um ='';
set @cm ='';
set @corrected ='';
set @correctme ='';
TRUNCATE TABLE tmp;
INSERT INTO tmp (material) SELECT material FROM vantilburgonline.productinfo;
WHILE (@rownumber < @totalrows) DO
SET @um = (SELECT alias01 FROM vantilburgonline.materials WHERE id=@rownumber);
-- gives 'um' value from column alias01, from table materials, row(X)
SET @cm = (SELECT material FROM vantilburgonline.materials WHERE id=@rownumber);
-- gives 'cm' value from column material, from table materials, row(X)
set @tmprow = 1;
set @totaltmprow =9000;
WHILE (@tmprow < @totaltmprow) DO
SET @correctme = (SELECT material FROM vantilburgonline.tmp WHERE id = @tmprow);
-- gives the value from column material from table tmp to correctme(X).
SET @correctme = REPLACE(@correctme,@um,@cm);
-- should run through column material from table productinfo and replace 'alias01' with correct 'material'.
SET @tmprow = @tmprow +1;
END WHILE;
SET @rownumber = @rownumber +1;
END WHILE;
END
虽然我确定alias01包含它应该在材料中找到的字符串。 Workbench此时也使用了9GB,我只能通过重新启动来解决这个问题。
答案 0 :(得分:1)
我建议您对materials
表进行更改,该表对多列(alias01 .. alias12)不实用。转换为规范化,可扩展的系统。它将有一个材质表和一个material_alias表。当它与您创建的当前表并排放置时,我使用2
命名它们。
drop table if exists materials2;
create table materials2
( material varchar(100) primary key, -- let's go with a natural key
active bool not null -- turn it LIVE and ON for string replacement of alias back to material name
-- so active is TRUE for ones to do replacement, or FALSE for skip
-- facilitates your testing of your synonyms, translations, slangs, etc
)engine=INNODB;
insert materials2 (material,active) values
('KARTON',true),
('Polyester',false),
('Lyocell',false),
('Linnen',true),
('Viscose',true),
('Scheerwol',false),
('Nylon',false),
('Leer',true),
('Polyurethaan',true),
('Polyacryl',true),
('Acryl',false),
('Modal',true),
('Acetaat',true),
('Papier',false),
('Wol',true),
('Zijde',true),
('Temcal',false),
('Polyamide',true),
('Wol-Merino',true),
('Elastan',true),
('Elastomultiester',true);
-- 21 rows
-- a few rows were skipped. The intent of them read as gibberish to me. Please review.
-- we need to restructure the materials2_alias table (after the first attempt)
-- 1. it might need special handling when `alias` is a legitimate substring of `material` (those 2 columns)
-- 2. it needs a unique composite index
drop table if exists materials2_alias;
create table materials2_alias
( id int auto_increment primary key,
material varchar(100) not null,
alias varchar(100) not null,
ais bool not null, -- Alias is Substring (alias is a legitimate substring of material, like Wo and Wol, respectively)
unique key(material,alias), -- Composite Index, do not allow dupe combos (only 1 row per combo)
foreign key `m2alias_m2` (material) references materials2(material)
)engine=INNODB;
insert materials2_alias (material,alias,ais) values
('KARTON','Cotton',false),('KARTON','Katoen',false),('KARTON','Pima',false),
('Polyester','Polyster',false),
('Lyocell','Lycocell',false),('Lyocell','Lyocel',false),
('Linnen','Linen',false),
('Viscose','Visose',false),('Viscose','Viskose',false),('Viscose','Viscoe',false),('Viscose','Voscose',false),
('Leer','Leder',false),('Leer','Lamsleder',false),('Leer','Varkensleder',false),('Leer','Schapenleder',false),('Leer','Geitenleder',false),
('Polyurethaan','Polyurethan',false),('Polyurethaan','PU',false),('Polyurethaan','Polyuretaan',false),('Polyurethaan','Polyurathane',false),('Polyurethaan','Polyurtaan',false),('Polyurethaan','Polyueretaan',false),
('Polyacryl','Polyacrylic',false),
('Acetaat','Leder',false),('Acetaat','Lamsleder',false),
('Wol','Schuurwol',false),('Wol','Wool',false),('Wol','WO',false),('Wol','Scheerwol',false),
('Zijde','Silk',false),('Zijde','Sede',false),
('Polyamide','Polyamie',false),('Polyamide','Polyamid',false),('Polyamide','Poliamide',false),
('Wol-Merino','Merino',false),
('Elastan','Elastaan',false),('Elastan','Spandex',false),('Elastan','Elataan',false),('Elastan','Elastane',false),
('Elastomultiester','elastomutltiester',false),('Elastomultiester','Elasomultiester',false);
-- this cleans up the above, where false should have been true
update materials2_alias
set ais=true
where instr(material,alias)>0;
-- 4 rows
有几个alter table
语句和其他内容。我会尝试记录它们或链接到它们。考虑到你有几百行代码,我只是想捕捉一些东西来分享。但是我的归结为一个简单的代码块,你可以把它放在一个循环中。
更新进入循环:
UPDATE productinfo pi
join materials2_alias ma
on instr( pi.material, concat(',',ma.alias,',') )>0
join materials2 m
on m.material=ma.material and m.active=true
set pi.material=replace(lower(pi.material),lower(ma.alias),lower(ma.material)),
pi.touchCount=pi.touchCount+1;
关于更新的一些注意事项:
-- Note, pi.material starts and ends with a comma.
-- I forced that during the ETL. But `ma.alias` does not contain commas.
-- So add the commas with a concat() within the "Update with a Join" pattern shown
--
-- Note that the commas solved the problem with the Wol - Wo
嗯,特别是以下4个。
select * from materials2_alias
where ais=true
order by material,alias;
+----+------------+----------+-----+
| id | material | alias | ais |
+----+------------+----------+-----+
| 6 | Lyocell | Lyocel | 1 |
| 33 | Polyamide | Polyamid | 1 |
| 28 | Wol | WO | 1 |
| 35 | Wol-Merino | Merino | 1 |
+----+------------+----------+-----+
-- instr() is not case sensitive except for binary strings
-- REPLACE(str,from_str,to_str); -- case sensitive
-- http://dev.mysql.com/doc/refman/5.7/en/string-functions.html#function_replace
--
-- so the update uses lower() or this won't work due to replace() case sensitivity
--
存储过程:
DROP PROCEDURE if exists touchCounts;
DELIMITER $$
CREATE PROCEDURE touchCounts()
BEGIN
select touchCount,count(*) as rowCount
from productinfo
group by touchCount
order by touchCount;
END $$
DELIMITER ;
当该存储过程在后续调用(下一次调用)中返回相同的行数时,您已完成通过更新修改material
列。
该存储过程可以自然地为rowcount返回out
参数。但是现在已经很晚了。
对于您身边的最后一个数据集,需要调用update语句4次。这就像我平庸的笔记本电脑上的13秒。这个想法自然是灵活的,如果你愿意,每种材料可以有数百个别名。
我把它停在github,因为它太多了。