Vla*_*lad 3 regex sql postgresql sql-update postgresql-10
我正在尝试清理一个表,该表有一个非常混乱的 varchar 列,其中包含以下条目:
<u><font color="#0000FF"><a href="http://virginialidar.com/index-3.html#.VgLbFPm6e73" target="_blank">VA Lidar</a></font></u> OR <u><font color="#0000FF"><a href="https://inport.nmfs.noaa.gov/inport/item/50122" target="_blank">InPort Metadata</a></font></u>
Run Code Online (Sandbox Code Playgroud)
我想通过仅保留 html 链接来更新列,如果有多个链接,则用昏迷将它们分开。理想情况下,我会做这样的事情:
UPDATE mytable
SET column = array_to_string(regexp_matches(column,'(?<=href=").+?(?=\")','g') , ',');
Run Code Online (Sandbox Code Playgroud)
但不幸的是,这会在 Postgres 10 中返回一个错误:
ERROR: set-returning functions are not allowed in UPDATE
Run Code Online (Sandbox Code Playgroud)
我假设regexp_matches()是所说的设置返回功能。关于如何实现这一目标的任何想法?
1.
您不需要将相关子查询建立在基表的单独实例上(就像到目前为止建议的两个答案)。那会白白做更多的工作。
2.
对于简单的情况,ARRAY 构造函数比array_agg(). 看:
3.
我使用没有前瞻和后视约束和括号的正则表达式:href="([^"]+)
请参阅查询 1。
这是有效的,因为括号内的子表达式被regexp_matches()(和其他几个 Postgres regexp 函数)捕获。所以我们可以用普通的括号替换更复杂的约束。手册regexp_match():
如果找到匹配项,并且 不
pattern包含带括号的子表达式,则结果是包含与整个模式匹配的子字符串的单元素文本数组。如果找到匹配项,并且*pattern*包含带括号的子表达式,则结果是一个文本数组,其n'th 元素是n与模式的'th 带括号的子表达式匹配的子字符串
如果没有匹配,则此函数不返回行,如果有匹配并且没有给出 g 标志,则返回一行,或者
N如果有 N 个匹配并且给出 g 标志,则返回行。每个返回的行是一个文本数组,包含整个匹配的子字符串或匹配模式的括号子表达式的子字符串,正如上面对regexp_match.
4.
regexp_matches()返回一组数组 ( setof text[]) 的原因是:正则表达式不仅可以在单个字符串中多次匹配(因此是set),它还可以为每个匹配生成多个字符串,并带有多个捕获括号(因此是数组)。此正则表达式不会发生,结果中的每个数组都包含一个元素。但是以后的读者千万不要掉入陷阱:
当将生成的一维数组提供给生成二维数组的array_agg()(或 ARRAY 构造函数)时 - 这甚至是可能的,因为 Postgres 9.5 添加了array_agg()接受数组输入的变体。看:
但是,引用手册:
输入必须具有相同的维度,并且不能为空或 NULL
我认为这永远不会失败,因为相同的正则表达式总是产生相同数量的数组元素。我们的总是产生一种元素。但这可能与其他正则表达式不同。如果是这样,有多种选择:
只取第一个元素(regexp_matches(...))[1]。请参阅查询 2。
取消嵌套数组并string_agg()在基本元素上使用。请参阅查询 3。
每种方法也适用于此。
UPDATE tbl t
SET col = (
SELECT array_to_string(ARRAY(SELECT regexp_matches(col, 'href="([^"]+)', 'g')), ',')
);
Run Code Online (Sandbox Code Playgroud)
没有匹配项的列被设置为''(空字符串)。
UPDATE tbl
SET col = (
SELECT string_agg(t.arr[1], ',')
FROM regexp_matches(col, 'href="([^"]+)', 'g') t(arr)
);
Run Code Online (Sandbox Code Playgroud)
没有匹配项的列设置为NULL.
UPDATE tbl
SET col = (
SELECT string_agg(elem, ',')
FROM regexp_matches(col, 'href="([^"]+)', 'g') t(arr)
, unnest(t.arr) elem
);
Run Code Online (Sandbox Code Playgroud)
没有匹配项的列设置为NULL.
db<> fiddle here(带有扩展的测试用例)