Php 如何替换MySQL字符串中特定字符的每个其他实例?
如何用查询替换mysql列中的值,例如,列为Php 如何替换MySQL字符串中特定字符的每个其他实例?,php,mysql,sql,string,replace,Php,Mysql,Sql,String,Replace,如何用查询替换mysql列中的值,例如,列为options及其类型为varchar(255) 从 到 我是这样用php做的 <?php $str = "A|10|B|20|C|30"; $arr = explode("|",$str); $newArr = array(); for($i=0;$i<count($arr);$i+=2){ if($arr[$i] && $arr[$i+1]){ $newArr
options
及其类型为varchar(255)
从
到
我是这样用php做的
<?php
$str = "A|10|B|20|C|30";
$arr = explode("|",$str);
$newArr = array();
for($i=0;$i<count($arr);$i+=2){
if($arr[$i] && $arr[$i+1]){
$newArr[] = $arr[$i]."|".$arr[$i+1];
}
}
echo "Before:".$str."\n";
echo "After :".implode(",",$newArr);
?>
因此,我不想使用PHP,而是希望在MySQL中执行此操作。嗯,我想您正在尝试这样做
SELECT GROUP_CONCAT(CONCAT(options,",") SEPARATOR "|") FROM Table.name;
我简单地解释一下,我为每一行取结果,然后连接“,”并用分隔符“|”连接所有行。
您必须用表的名称更改Table.name
如果您想连接一个或多个值,如A、B、C(您没有解释ABC值来自何处,所以让我们假设ValueWherebDiscomingFrom):
如果我的桌子是这样的:
id | ValueWhereABCisComingFrom | options
0 | A | 10
1 | B | 20
2 | C | 30
你会有这样的东西:
A|10,B|20,C|30
编辑1
在那种情况下是没有办法的。mysql中没有像preg_replace这样的函数。你所能做的就是替换所有像这样的“|”
在MariaDB中,有这样一个函数,所以您可以尝试从一个基传递到另一个基。但仅使用MYSQL是不行的://p>不使用存储过程,我将分两步完成:
updateoptions set options=insert(选项,定位(“|”),选项,定位(“|”,选项)+1),1,”,”;
updateoptions set options=insert(选项,定位(“|”),选项,定位(“|”),选项,长度(选项)-定位(“,”,反转(选项))+1)+1,“,”);
在哪里=
从选项中选择最大值(圆形(((长度(选项)-长度(替换(选项“|”),”)-1)/2)-1);
(或者不必费心计算,继续执行查询,只要它不告诉您“0行受影响”)id选项
1 A | 10 | B | 20 | C | 30
2 A |正| B |负
3 A | 10 | B | 20 | C | 30 | D | 40 | E | 50 | F | 60
4 A |正| B |负| C |中性| D |邓诺
结果:
id选项
1 A | 10,B | 20,C | 30
2 A |正,B |负
3 A | 10,B | 20,C | 30,D | 40,E | 50,F | 60
4 A |正,B |负,C |中性,D | Dunno
(稍后我将提供解释)您可以通过创建函数来完成
CREATE FUNCTION doiterate(str TEXT, i INT, next INT, isp TINYINT(1))
RETURNS TEXT
BEGIN
myloop: LOOP
IF next = 0 THEN
LEAVE myloop;
END IF;
IF isp = TRUE THEN
set str = insert(str, i, 1, ',');
set isp = FALSE;
set i = next;
set next = locate('|', str, i + 1);
ITERATE myloop;
ELSE
set isp = TRUE;
set i = next;
set next = locate('|', str, i + 1);
ITERATE myloop;
END IF;
LEAVE myloop;
END LOOP;
return str;
END;
这样说:
SELECT t.`column`,
@loc := locate('|', t.`column`) as position,
@next := locate('|', t.`column`, @loc +1) as next,
@isp := 0 is_pipe,
@r := doiterate(t.column, @loc, @next, @isp) as returnstring
from test t;
我想你会很聪明的
- 更改表名和列名
- 将其插入到更新请求中
选择id,
选项为'before`,
reg_替换(选项,
“\\\\..\\\\”,--2个管道符号,中间有任何文本
“\\\$”,替换第二个管道符号
“,”,--替换为逗号
假,--非贪婪匹配
2,--最小匹配长度=2(2个管道符号)
0,--无最大匹配长度
0,--最小子匹配长度=1(1个管道符号)
0--最大子匹配长度=1(1个管道符号)
)在……之后`
来自tbl;
> p>您应该考虑将数据存储在规范化模式中。在您的情况下,该表应如下所示:
| id | k | v |
|----|---|----------|
| 1 | A | 10 |
| 1 | B | 20 |
| 1 | C | 30 |
| 2 | A | Positive |
| 2 | B | Negative |
这个模式更灵活,您将看到原因
那么,如何将给定的数据转换成新的模式呢?您需要一个包含序列号的辅助表。由于您的列是varchar(255)
,因此只能在其中存储128个值(+127个分隔符)。但是让我们创建1000个数字。您可以使用任何具有足够行的表。但是,由于任何MySQL服务器都有information\u schema.columns
表,所以我将使用它
drop table if exists helper_sequence;
create table helper_sequence (i int auto_increment primary key)
select null as i
from information_schema.columns c1
join information_schema.columns c2
limit 1000;
通过连接两个表,我们将使用这些数字作为字符串中值的位置
要从分隔字符串中提取值,可以使用substring\u index()
函数。位置i
处的值将为
substring_index(substring_index(t.options, '|', i ), '|', -1)
在字符串中,有一系列键,后跟其值。钥匙的位置是奇数。因此,如果键的位置是i
,则相应值的位置将是i+1
要获取字符串中分隔符的数目并限制我们的联接,我们可以使用
char_length(t.options) - char_length(replace(t.options, '|', ''))
以规范化形式存储数据的查询为:
create table normalized_table
select t.id
, substring_index(substring_index(t.options, '|', i ), '|', -1) as k
, substring_index(substring_index(t.options, '|', i+1), '|', -1) as v
from old_table t
join helper_sequence s
on s.i <= char_length(t.options) - char_length(replace(t.options, '|', ''))
where s.i % 2 = 1
那么,为什么这种格式是更好的选择呢?除了许多其他原因外,其中一个原因是您可以使用
select id, group_concat(concat(k, '|', v) order by k separator '|') as options
from normalized_table
group by id;
| id | options |
|----|-----------------------|
| 1 | A|10|B|20|C|30 |
| 2 | A|Positive|B|Negative |
或者按照您想要的格式
select id, group_concat(concat(k, '|', v) order by k separator ',') as options
from normalized_table
group by id;
| id | options |
|----|-----------------------|
| 1 | A|10,B|20,C|30 |
| 2 | A|Positive,B|Negative |
如果您不关心规范化,只希望完成此任务,那么可以使用
update old_table o
join (
select id, group_concat(concat(k, '|', v) order by k separator ',') as options
from normalized_table
group by id
) n using (id)
set o.options = n.options;
然后放下标准化_表
但是,您将无法使用像这样的简单查询
select *
from normalized_table
where k = 'A'
请参见因此,您想在MySQL中代替PHP执行此操作吗?是的,您明白了,我正在复制您在我的问题中的评论。请向我们显示模式。列为options
,其类型为varchar(255)
好的,让我重新措辞。A
来自哪里?10
来自哪里?它们在不同的列中吗?您已经使用了什么查询?我已经编辑了我的答案,但很抱歉,只有在MySQL中无法做到这一点。
| id | k | v |
|----|---|----------|
| 1 | A | 10 |
| 1 | B | 20 |
| 1 | C | 30 |
| 2 | A | Positive |
| 2 | B | Negative |
select id, group_concat(concat(k, '|', v) order by k separator '|') as options
from normalized_table
group by id;
| id | options |
|----|-----------------------|
| 1 | A|10|B|20|C|30 |
| 2 | A|Positive|B|Negative |
select id, group_concat(concat(k, '|', v) order by k separator ',') as options
from normalized_table
group by id;
| id | options |
|----|-----------------------|
| 1 | A|10,B|20,C|30 |
| 2 | A|Positive,B|Negative |
update old_table o
join (
select id, group_concat(concat(k, '|', v) order by k separator ',') as options
from normalized_table
group by id
) n using (id)
set o.options = n.options;
select *
from normalized_table
where k = 'A'