加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 站长学院 > PHP教程 > 正文

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 SPLIT_STR function:

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 records
    
  

  
How 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)

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读