我下面有一个表,我的问题是如何根据参数更新mysql中的列。
+---+------------+-------------+
| id| A | B |
+---+------------+-------------+
| 1 | a b a a | |
| 2 | b c a | |
| 3 | b d c | |
| 4 | a | |
+---+------------+-------------+
预期结果应计算“a”然后更新列B的出现次数,如下所示。当然,我需要使用正则表达式来计算“a”的数量
+---+------------+-------------+
| | A | B |
+---+------------+-------------+
| 1 | a b a a | 3 |
| 2 | b c a | 1 |
| 3 | b d c | 0 |
| 4 | a | 1 |
+---+------------+-------------+
答案 0 :(得分:1)
这可以在单个SQL语句中完成。 (不幸的是,这种方法不能满足使用正则表达式的要求。编辑:请参阅下面的后续内容,了解使用正则表达式的不优雅且低效的方法。)
我们可以计算列A
中字符'a'的出现次数,并将列B
设置为计数,并使用如下查询:
UPDATE mytable t
SET t.B = ( CHAR_LENGTH(t.A) - CHAR_LENGTH(REPLACE(t.A,'a','')) )
让我们解开一点点。它是UPDATE
语句,没有WHERE
子句,因此我们将访问并可能更新mytable
中的每一行。 (我们正在分配一个表别名t
。这不是必需的,但我们将使用该别名限定我们以后对列A
和B
的引用,以使某些人更清楚读取那些引用表中列的SQL语句。
在下一行,我们有一个简单的SET
子句,为列B
指定一个值。
这是下一个表达式,即我们分配给列B
的值,我们应该解压缩一点。
要获得'a'
个字符的计数,我们可以使用一个小技巧:我们知道'a'
字符的长度恰好是一个字符。
“技巧”是使用REPLACE
函数来搜索所有出现的字符'a'
,并删除它们(用零长度字符串替换它们)。然后我们可以比较两个字符串的(字符数)的长度。区别在于原始字符串中'a'
个字符的数量。
作为这些表达方式如何运作的演示:
SELECT t.foo AS foo
, REPLACE(t.foo,'a','') AS foo_2
, CHAR_LENGTH(t.foo) AS len
, CHAR_LENGTH(REPLACE(t.foo,'a','')) AS len_2
, CHAR_LENGTH(t.foo) - CHAR_LENGTH(REPLACE(t.foo,'a','')) AS `len-len_2`
FROM ( SELECT 'a b a a' AS foo
UNION ALL SELECT 'b c a'
UNION ALL SELECT 'b c d'
UNION ALL SELECT 'a '
) t
从该查询返回:
foo foo_2 len len_2 len-len_2
------- ------ ------ ------ ---------
a b a a b 7 4 3
b c a b c 5 4 1
b c d b c d 5 5 0
a 3 2 1
注意:返回的内容基本上是删除的字符数。因此,如果我们想要计算多个字符串的出现次数,例如:cat
,我们需要考虑到这一点。
将返回值除以cat
中的字符数是一种方法。或者,我们可以将字符串cat
替换为长度为两个字符的字符串,例如'xx'
,所以长度的差异是每次出现一个字符。
<强>后续强>
原始问题询问如何使用正则表达式计算'a'字符。我的第一个想法是MySQL REGEXP
是不可能的,因为从那里返回的是NULL,0或1.但是考虑一下,它可以完成,如果我们计算一些有限的出现次数。可以检查字符串是否包含至少一个'a'字符,这非常简单:
'a b a a' REGEXP 'a'
如果匹配则返回1,如果不匹配则返回0。也可以检查字符串是否包含至少两个'a'字符。这也非常简单:
'a b a a' REGEXP 'a.*a'
如果我们将上面两个表达式的结果加在一起,我们可以得到“a”字符数的0,1或2计数。
我们可以重复相同的模式,将其扩展为匹配3,4,5等“a”字符。
它并不优雅,我们当然不想知道CPU在进行所有这些比较时会有多热情。但它确实返回指定的结果,直到某个有限的最大计数。在这个例子中,六个。 (包含六个以上'a'字符的字符串将返回6。
作为示范:
SELECT t.foo
, (t.foo REGEXP CONCAT('.*',REPEAT('a.*',1)))
+ (t.foo REGEXP CONCAT('.*',REPEAT('a.*',2)))
+ (t.foo REGEXP CONCAT('.*',REPEAT('a.*',3)))
+ (t.foo REGEXP CONCAT('.*',REPEAT('a.*',4)))
+ (t.foo REGEXP CONCAT('.*',REPEAT('a.*',5)))
+ (t.foo REGEXP CONCAT('.*',REPEAT('a.*',6)))
AS cnt_a
FROM ( SELECT 'a b a a' AS foo
UNION ALL SELECT 'b c a'
UNION ALL SELECT 'b c d'
UNION ALL SELECT 'a '
) t
答案 1 :(得分:0)
选项1:纯SQL
用空字符串替换要计数的子字符串。通过比较结果字符串和原始字符串的长度,您可以知道有多少次出现:
update table set b = (length(a) - length(replace(a,'a',''))) / length('a')
您可以用任意长度的任何字符串替换常量字符串'a'
。
选项2:使用PHP和SQL
您可以使用PHP迭代所有行并使用substr_count
函数来计算子字符串的出现次数(在您的情况下,子字符串将是'a')。然后更新该行中b
的值。假设字段id
是您的主键:
$query = $pdo->query("select id,a from table");
while($row = $query->fetch()) {
$b = substr_count($row['a']);
$id = $row['id'];
$pdo->query("update table set b = $b where id = $id");
}
请注意,这种方法效率不高。
答案 2 :(得分:0)
UPDATE Table SET B = i.b
FROM (SELECT LENGTH(A) - LENGTH(REPLACE(A, 'a', '')) as b from Table ) i
WHERE i.ID = Table.ID