让我们将您问题中的查询简化为您要询问的组成部分。一旦我们看到它们是如何单独工作的,也许整个查询会更有意义。
首先,~(波浪号)是POSIX,区分大小写的regular expression operator。链接的 PostgreSQL 文档提供了它及其兄弟运算符的简要描述和使用示例:
| Operator |
Description |
Example |
~ |
Matches regular expression, case sensitive |
'thomas' ~ '.*thomas.*' |
~* |
Matches regular expression, case insensitive |
'thomas' ~* '.*Thomas.*' |
!~ |
Does not match regular expression, case sensitive |
'thomas' !~ '.*Thomas.*' |
!~* |
Does not match regular expression, case insensitive |
'thomas' !~* '.*vadim.*' |
我们可以看到每个运算符都有两个操作数:左边是一个常量字符串,右边是一个模式。如果左边的字符串与右边的模式匹配,则语句为true,否则为false。
在您询问的运算符的给定示例中,'thomas' 与标准正则表达式规则的模式 '.*thomas.*' 匹配。 '.*' 前后缀表示“匹配 any character (except newline) 任意次数 (zero or more)”。整个模式的意思是,“匹配任何字符任意多次,然后匹配文字字符串 'thomas',然后任意匹配任意字符”。一个这样的匹配是'john thomas jones',其中'john ' 匹配第一个'.*',' jones' 匹配第二个'.*'。
我不认为这是一个很好的例子,因为它在功能上等同于'thomas' LIKE '%thomas%',后者可能运行得更快,among other benefits like being a SQL-standard operator。
一个更好的例子是问题中使用'^[0-9]' 模式的查询。暂时将^ 放在一边,这个模式的意思是“匹配0-9 (0, 1, 2, ..., 8, 9) 中的任何字符”,如果你使用LIKE 运营商:field LIKE '^0' OR field LIKE '^1' OR field LIKE '^2' ....
^ 运算符不是 PostgreSQL 特定的。相反,它是正则表达式中的特殊字符,具有两种含义之一(aside from its use as a literal character; more about that in this answer):
- 匹配应从行/字符串的开头开始。
例如,字符串“Hello, World!” 将包含与模式'World' 的匹配项,因为其中出现了单词“World”,但不会包含与模式'^World' 的匹配项,因为单词“World”不在开头字符串。
字符串“你好,世界!”将包含以下两种模式的匹配项:'Hello' 和 '^Hello',因为单词“Hello”位于字符串的开头。
- 在进行匹配时,给定的字符集应该被否定。
例如,模式[^0-9] 的意思是“匹配任何不在0-9 范围内的字符”。所以'a' 会匹配,'&' 会匹配,'G' 会匹配,但'7' 不会匹配,因为它在被排除的字符集中。
您问题中的查询使用两种含义中的第一种。模式'^[0-9]' 表示“匹配从字符串开头开始的0-9 范围内的任何字符”。所以'0123' 会匹配,因为字符串以“0”开头,但'a5' 不会匹配,因为字符串以“a”开头,这不是要匹配的字符集。
然后,回到您问题中的查询。相关部分内容如下:
1 count(distinct
2 case
3 when left(business_address, 1) ~ '^[0-9]'
4 then lower(split_part(business_address, ' ', 2))
5 else lower(split_part(business_address, ' ', 1))
6 end
7 ) as n_street
第 3 行包含一个正则表达式匹配,它将确定我们是否应该在整个 CASE 语句中使用这种情况。如果字符串与模式匹配,则表达式将为true,我们将使用这种情况。如果字符串与模式不匹配,则表达式将为false,我们将尝试下一个案例。
我们与模式匹配的字符串是left(business_address, 1)。 LEFT function 从字符串中获取第一个 n 字符。由于此处n 为“1”,因此返回字段business_address 的第一个字符。
我们试图匹配这个字符串的模式是'^[0-9]',我们已经说过,“匹配从字符串开头开始的 0-9 范围内的任何字符”。从技术上讲,我们在这里不需要^ 正则表达式运算符,因为LEFT(..., 1) 最多会返回一个字符(它将始终是结果字符串中的第一个字符)。
例如,如果business_address 是“123 Jones Street, Anytown, USA”,那么 LEFT(business_address, 1) 将返回匹配模式的“1”(因此表达式将为 true,我们将使用第一种情况)。
如果 business_address 是“Jones Plaza, Suite 123, Anytown, USA”,则 LEFT(business_address, 1) 将返回与模式不匹配的“J”(因为第一个字符是“J”,而不是在 0-9 范围内)。我们的表达式是false,我们将继续下一个案例。