php – MySQL – 如何规范化包含分隔符分隔ID的列
发布时间:2020-12-13 17:50:22 所属栏目:PHP教程 来源:网络整理
导读:我正在尝试规范化一个表,前一个开发人员设计的表包含一个包含管道分隔ID的列,该列链接到同一个表中的其他行. 客户表 id | aliases (VARCHAR)----------------------------1 | |4|58|762 | 3 |4 | |1|58|76... | 58 | |1|4|76... |76 | |1|4|58 因此,客户1,4,
我正在尝试规范化一个表,前一个开发人员设计的表包含一个包含管道分隔ID的列,该列链接到同一个表中的其他行.
客户表 id | aliases (VARCHAR) ---------------------------- 1 | |4|58|76 2 | 3 | 4 | |1|58|76 ... | 58 | |1|4|76 ... | 76 | |1|4|58 因此,客户1,4,58和76都是彼此的“别名”.客户2和3没有别名,因此该字段包含空字符串. 我想取消整个“别名”系统,并规范化数据,以便将其他所有客户映射到一条记录.所以我希望客户1,58和76的相关表数据都只映射到客户1. 我想我会填充一个新表,然后我可以加入并在其他表上执行更新. 加入表格 id | customer_id | alias_id ------------------------------- 1 | 1 | 4 2 | 1 | 58 3 | 1 | 76 如何从第一个表中获取上述格式的数据?如果这将是纯SQL中的绝对噩梦,我将编写一个PHP脚本,尝试执行此工作并插入数据. 解决方法
当我开始回答这个问题时,我认为这将是快速而简单的,因为我在SQL Server中做过一次非常类似的事情,但证明了翻译中的概念已经发展到这个完整的解决方案中.
您的问题中不明确的一个警告是,您是否有条件声明主要ID与别名ID.例如,此解决方案将允许1具有别名4以及4具有别名1,这与简化示例问题中提供的数据一致. 要为此示例设置数据,我使用了以下结构: CREATE TABLE notnormal_customers ( id INT NOT NULL PRIMARY KEY,aliases VARCHAR(10) ); INSERT INTO notnormal_customers (id,aliases) VALUES (1,'|4|58|76'),(2,''),(3,(4,'|1|58|76'),(58,'|1|4|76'),(76,'|1|4|58'); 首先,为了表示一个客户到多个别名的一对多关系,我创建了这个表: CREATE TABLE customer_aliases ( primary_id INT NOT NULL,alias_id INT NOT NULL,FOREIGN KEY (primary_id) REFERENCES notnormal_customers(id),FOREIGN KEY (alias_id) REFERENCES notnormal_customers(id),/* clustered primary key prevents duplicates */ PRIMARY KEY (primary_id,alias_id) ) 最重要的是,我们将使用custom CREATE FUNCTION SPLIT_STR( x VARCHAR(255),delim VARCHAR(12),pos INT ) RETURNS VARCHAR(255) RETURN REPLACE(SUBSTRING(SUBSTRING_INDEX(x,delim,pos),LENGTH(SUBSTRING_INDEX(x,pos -1)) + 1),''); 然后我们将创建一个存储过程来完成所有工作.代码注释了对源引用的注释. DELIMITER $$ CREATE PROCEDURE normalize_customers() BEGIN DECLARE cust_id INT DEFAULT 0; DECLARE al_id INT UNSIGNED DEFAULT 0; DECLARE alias_str VARCHAR(10) DEFAULT ''; /* set the value of the string delimiter */ DECLARE string_delim CHAR(1) DEFAULT '|'; DECLARE count_aliases INT DEFAULT 0; DECLARE i INT DEFAULT 1; /* use cursor to iterate through all customer recordsHow To Loop Through A Result Set in MySQL Strored Procedure*/ DECLARE done INT DEFAULT 0; DECLARE cur CURSOR FOR SELECT `id`,`aliases` FROM `notnormal_customers`; DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1; OPEN cur; read_loop: LOOP /* Fetch one record from CURSOR and set to customer id and alias string. If not found then `done` will be set to 1 by continue handler. */ FETCH cur INTO cust_id,alias_str; IF done THEN /* If done set to 1 then exit the loop,else continue. */ LEAVE read_loop; END IF; /* skip to next record if no aliases */ IF alias_str = '' THEN ITERATE read_loop; END IF; /* get number of aliases Count Occurrence of Character in a String Using?MySQL */ SET count_aliases = LENGTH(alias_str) - LENGTH(REPLACE(alias_str,string_delim,'')); /* strip off the first pipe to make it compatible with our SPLIT_STR function */ SET alias_str = SUBSTR(alias_str,2); /* iterate and get each alias from custom split string function https://stackoverflow.com/questions/18304857/split-delimited-string-value-into-rows */ WHILE i <= count_aliases DO /* get the next alias id */ SET al_id = CAST(SPLIT_STR(alias_str,i) AS UNSIGNED); /* REPLACE existing values instead of insert to prevent errors on primary key */ REPLACE INTO customer_aliases (primary_id,alias_id) VALUES (cust_id,al_id); SET i = i+1; END WHILE; SET i = 1; END LOOP; CLOSE cur; END$$ DELIMITER ; 最后,您可以通过调用以下命令运行它: CALL normalize_customers(); 然后你可以在控制台中检查数据: mysql> select * from customer_aliases; +------------+----------+ | primary_id | alias_id | +------------+----------+ | 4 | 1 | | 58 | 1 | | 76 | 1 | | 1 | 4 | | 58 | 4 | | 76 | 4 | | 1 | 58 | | 4 | 58 | | 76 | 58 | | 1 | 76 | | 4 | 76 | | 58 | 76 | +------------+----------+ 12 rows in set (0.00 sec) (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |