替换文本表达式中的多个ID

时间:2016-01-11 12:51:09

标签: sql regex postgresql common-table-expression

我已经检查过了,之前我还没有找到这样的问题。

我有一个名为tests的表,其中(简化)包含3列。

 |  id  |  name  |      expression      |
=========================================
 |  1   |  width |                      |
 |  2   | length |                      |
 |  3   |  area  |  [1] * [2]           |

我需要一个查询,给定一个测试ID可以返回完全限定的表达式,即用相关名称替换表达式中的ID号。

表达式的ID号始终在方括号内。

我已经遵循了几条路径,但这是我当前的查询,但它并没有将名称替换为一个字符串。

查询:

WITH regexmatch AS
(
  SELECT
    id,
    expression,
    (regexp_matches(expression, '\[(\d+)\]', 'g'))[1] AS replaceid
  FROM
    test
  WHERE
    expression IS NOT NULL
  AND
    id = 3
  GROUP BY
    id, expression
)
SELECT
  regexmatch.id,
  regexmatch.expression,
  REPLACE(regexmatch.expression, replaceid, (SELECT name FROM test WHERE id = replaceid::bigint))
FROM
  regexmatch

输出:

 |  id  |  expression  |      replacement      |
================================================
 |  1   |  [1] * [2]   |  [width] * [2]        |
 |  2   |  [1] * [2]   |  [1] * [length]       |

这个查询是否可行,如果可以,我该如何去做呢?

1 个答案:

答案 0 :(得分:1)

一种方法是递归公用表表达式:

CREATE TABLE test(id INT, "name" VARCHAR(100), expression VARCHAR(100));

INSERT INTO test(id,  "name", expression)
SELECT 1,  'width', NULL                      
UNION ALL SELECT 2, 'length', NULL                      
UNION ALL SELECT 3, 'area'  ,  '[1] * [2]' 
UNION ALL SELECT 4, 'height', NULL
UNION ALL SELECT 5, 'volume', '[3] * [4]'       
UNION ALL SELECT 6, 'volumne_alt', '[2]^3';

查询:

WITH RECURSIVE cte AS (
  SELECT id,  expression::varchar(10000), "name"
         ,(regexp_matches(expression, '\[(\d+)\]'))[1] AS repid
  FROM  test
  WHERE expression IS NOT NULL  
  UNION ALL
  SELECT id, REPLACE(expression, repid, (SELECT name 
                                         FROM test 
                                         WHERE id = repid::int))::varchar(10000)
          ,"name",(regexp_matches(expression, '\[(\d+)\]'))[1]    
  FROM cte c
  WHERE c.expression ~ '(.*)\[(\d+)\](.*)'
)
SELECT id, "name", expression
FROM cte
WHERE expression !~ '(.*)\[(\d+)\](.*)'
ORDER BY id;

SqlFiddleDemo

输出:

╔═════╦══════════════╦════════════════════╗
║ id  ║    name      ║     expression     ║
╠═════╬══════════════╬════════════════════╣
║  3  ║ area         ║ [width] * [length] ║
║  5  ║ volume       ║ [area] * [height]  ║
║  6  ║ volumne_alt  ║ [length]^3         ║
╚═════╩══════════════╩════════════════════╝

使用表格UPDATE

WITH cte AS
(...
)
UPDATE test AS t
SET expression = c.expression
FROM cte AS c
WHERE t.id = c.id AND c.expression !~ '(.*)\[(\d+)\](.*)';

SqlFiddleDemo2

输出:

╔═════╦══════════════╦════════════════════╗
║ id  ║    name      ║     expression     ║
╠═════╬══════════════╬════════════════════╣
║  1  ║ width        ║ (null)             ║
║  2  ║ length       ║ (null)             ║
║  3  ║ area         ║ [width] * [length] ║
║  4  ║ height       ║ (null)             ║
║  5  ║ volume       ║ [area] * [height]  ║
║  6  ║ volumne_alt  ║ [length]^3         ║
╚═════╩══════════════╩════════════════════╝